-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(event-invocation-type): Add support for Event invocation type #749
Conversation
2bcf4bd
to
4cda7f8
Compare
Does this mean we'll no longer get:
? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ejhayes Thanks for adding this! It looks really solid. I have a couple minor comments to address but overall great job! I even pulled and played with it locally.
Could you please rebase on top of develop as well? There were lots of changes introduced to support Layers recently.
|
||
if not request_data: | ||
request_data = b'{}' | ||
LOG.debug('Async invocation: %s, requestId=%s', function_name, request_id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This requestId will not match the requestId in the container. This will be very confusing when reading the output. Can we not add the request id?
Ideally, if we could set the id from SAM CLI in the docker container, it would be much better but last time I checked, their was a way to do this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I just checked awslambda.js
in the docker container and it looks like awsRequestId
is set from invokeId
. invokeId
is set to uuid()
. If we could just allow an environment variable to overwrite this value then we could pass it from SAM CLI. I don't know where the code for awslambda.js
is coming from otherwise I'd make this change myself:
var fs = require('fs')
var crypto = require('crypto')
var HANDLER = process.argv[2] || process.env.AWS_LAMBDA_FUNCTION_HANDLER || process.env._HANDLER || 'index.handler'
var EVENT_BODY = process.argv[3] || process.env.AWS_LAMBDA_EVENT_BODY ||
(process.env.DOCKER_LAMBDA_USE_STDIN && fs.readFileSync('/dev/stdin', 'utf8')) || '{}'
var FN_NAME = process.env.AWS_LAMBDA_FUNCTION_NAME || 'test'
var VERSION = process.env.AWS_LAMBDA_FUNCTION_VERSION || '$LATEST'
var MEM_SIZE = process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE || '1536'
var TIMEOUT = process.env.AWS_LAMBDA_FUNCTION_TIMEOUT || '300'
var REGION = process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION || 'us-east-1'
var ACCOUNT_ID = process.env.AWS_ACCOUNT_ID || randomAccountId()
var ACCESS_KEY_ID = process.env.AWS_ACCESS_KEY_ID || 'SOME_ACCESS_KEY_ID'
var SECRET_ACCESS_KEY = process.env.AWS_SECRET_ACCESS_KEY || 'SOME_SECRET_ACCESS_KEY'
var SESSION_TOKEN = process.env.AWS_SESSION_TOKEN
var INVOKED_ARN = process.env.AWS_LAMBDA_FUNCTION_INVOKED_ARN || arn(REGION, ACCOUNT_ID, FN_NAME)
var INVOKE_ID = process.env.AWS_LAMBDA_INVOKE_ID || uuid() // TODO: add this line
function consoleLog(str) {
process.stderr.write(formatConsole(str))
}
function systemLog(str) {
process.stderr.write(formatSystem(str) + '\n')
}
function systemErr(str) {
process.stderr.write(formatErr(str) + '\n')
}
function handleResult(resultStr, cb) {
if (!process.stdout.write('\n' + resultStr + '\n')) {
process.stdout.once('drain', cb)
} else {
process.nextTick(cb)
}
}
// Don't think this can be done in the Docker image
process.umask(2)
process.env.AWS_LAMBDA_FUNCTION_NAME = FN_NAME
process.env.AWS_LAMBDA_FUNCTION_VERSION = VERSION
process.env.AWS_LAMBDA_FUNCTION_MEMORY_SIZE = MEM_SIZE
process.env.AWS_LAMBDA_LOG_GROUP_NAME = '/aws/lambda/' + FN_NAME
process.env.AWS_LAMBDA_LOG_STREAM_NAME = new Date().toISOString().slice(0, 10).replace(/-/g, '/') +
'/[' + VERSION + ']' + crypto.randomBytes(16).toString('hex')
process.env.AWS_REGION = REGION
process.env.AWS_DEFAULT_REGION = REGION
process.env._HANDLER = HANDLER
var OPTIONS = {
initInvokeId: uuid(),
invokeId: INVOKE_ID, // TODO: update this
handler: HANDLER,
suppressInit: true,
credentials: {
key: ACCESS_KEY_ID,
secret: SECRET_ACCESS_KEY,
session: SESSION_TOKEN,
},
eventBody: EVENT_BODY,
contextObjects: {
// clientContext: '{}',
// cognitoIdentityId: undefined,
// cognitoPoolId: undefined,
},
invokedFunctionArn: INVOKED_ARN,
}
request_data = flask_request.get_data() | ||
thread = threading.Thread(target=self._invoke_sync_request, | ||
args=(function_name, request_data), | ||
kwargs={'stdout': stdout, 'stderr': stderr}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These can be in args as well.
|
||
if is_lambda_user_error_response: | ||
LOG.debug('Lambda error response: %s', lambda_response) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this really needed if we are sending this data back in the next line? My opinion is to remove this.
return self.service_response(lambda_response, | ||
{'Content-Type': 'application/json', 'x-amz-function-error': 'Unhandled'}, | ||
200) | ||
|
||
LOG.debug('Lambda returned success: %s', lambda_response) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as the above comment on LOG.debug
@@ -95,7 +95,7 @@ def test_invoke_with_log_type_not_None(self): | |||
|
|||
def test_invoke_with_invocation_type_not_RequestResponse(self): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should add explicit integ test for Invoke with --invocation-type Event
.
@patch('samcli.local.lambda_service.local_lambda_invoke_service.LocalLambdaInvokeService.service_response') | ||
@patch('samcli.local.lambda_service.local_lambda_invoke_service.LambdaOutputParser') | ||
@patch('samcli.local.lambda_service.local_lambda_invoke_service.request') | ||
def test_invoke_request_handler_async(self, request_mock, lambda_output_parser_mock, service_response_mock): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should be mocking out Thread here too and asserting the mock is called correctly.
@binarymist Yes. This PR is to add support for invoking a local function through |
@jfuss thanks for the input. AFK right now but will try to get this stuff addressed later this week. |
@ejhayes Just checking back. Have you gotten a chance to address feedback? Would love to get this into an upcoming release if you have some time to wrap it up. |
@ejhayes Hey! this is a cool feature to add, if are you able to address feedback, we can look at merging this in! |
@thesriram @jfuss somehow this got missed. Let me merge in the latest changes and address the feedback from earlier. I agree, it would definitely be good to get this into an upcoming release! |
Any progress? |
…away while the lambda function runs in a separate thread.
4cda7f8
to
4d7950a
Compare
Hi, has there been any progress with implementing the Event InvocationType in sam? Are there any workarounds for the time being? |
Hello, |
Another vote for getting support for Event invocation-type. I really need this. I'm trying to use RequestResponse as a work-around and it's painful |
Hey! Great work! I'd love this feature to be out soon. |
How about this feature? |
Would very much appreciate this feature, maybe someone can take over? |
Hello. Does anyone know if this PR is being considered for merge? Thanks in advance. |
This is still a good feature to add, however this looks like the PR is stalled. I am going to close this but if someone wants to re-pick this up, feel free to publish a new PR. |
It's a shame that this great feature has stalled. @jfuss Isn't the feedback addressed as @bennebbenneb suggests? |
This is a much needed feature, any update? |
Waiting as well |
@ejhayes @jfuss It's been about 5 years since this PR was initially opened and after getting an error trying to use the Event invocation type in aws sam locally, I stumbled upon this PR and I'm very surprised that even after five years, this is still an unresolved issue. Please do something, thanks! |
Here's another vote to support Event invocation locally. |
Another vote. Would be awesome if this can be implemented |
Here's a workaround I use to call a local lambda asynchronously. Call it over HTTP, wait for a moment for the request to go through, then abort the request and move on. This is good enough for my local testing because it allows the invoked function to continue running, while the calling function can exit and let API gateway request complete normally without timing out. This is Typescript/Node.js, but should be implementable in other languages. if (process.env.AWS_SAM_LOCAL === 'true') {
const url = `http://host.docker.internal:3011/2015-03-31/functions/${FunctionName}/invocations`;
const controller = new AbortController();
fetch(url, {
method: 'POST',
signal: controller.signal,
body: Payload,
headers: {
'Content-Type': 'application/json',
},
}).catch(() => {});
await new Promise<void>(resolve =>
setTimeout(() => {
controller.abort();
resolve();
}, 1500),
);
} else {
await new Lambda().invoke({ FunctionName, InvocationType: 'Event', Payload }).promise();
} |
Does anyone know if this is actively being worked on (e.g. In another PR / issue)? |
Issue #, if available:
This is mentioned in several different issues:
#510
#207
#12
Description of changes:
This adds support for the event invocation type. #508 made it possible to call local lambda using AWS CLI, but only for
RequestResponse
invocation type. This adds on to the local lambda invocation functionality by allowingEvent
invocation type.This allows multiple lambda functions to call other lambda functions without having to wait for them to return (i.e.
RequestResponse
invocation type).Usage
Run local lambda service:
You'll see that local lambda service is at 127.0.0.1:3001:
Test invocation using CLI:
This can also be done within a lambda function. Note that the endpoint referenced cannot be 127.0.0.1 since the function code will be running within a container. Docker for Mac has a special hostname for the underlying host machine named
host.docker.internal
. Additional documentation for that can be found here:By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.