Skip to content
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

Support for asynchronous lambda invocation with integration type AWS #5898

Merged
merged 2 commits into from Mar 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 15 additions & 0 deletions docs/providers/aws/events/apigateway.md
Expand Up @@ -483,6 +483,21 @@ functions:
- nickname - nickname
``` ```


### Using asyncronous integration

Use `async: true` when integrating a lambda function using event invocation. This lets API Gateway to return immediately while the lambda continues running. If not othewise speficied integration type will be `AWS`.

```yml
functions:
create:
handler: posts.create
events:
- http:
path: posts/create
method: post
async: true # default is false
```

### Catching Exceptions In Your Lambda Function ### Catching Exceptions In Your Lambda Function


In case an exception is thrown in your lambda function AWS will send an error message with `Process exited before completing request`. This will be caught by the regular expression for the 500 HTTP status and the 500 status will be returned. In case an exception is thrown in your lambda function AWS will send an error message with `Process exited before completing request`. This will be caught by the regular expression for the 500 HTTP status and the 500 status will be returned.
Expand Down
Expand Up @@ -379,6 +379,47 @@ describe('#compileMethods()', () => {
}); });
}); });


it('should add request parameter when async config is used', () => {
awsCompileApigEvents.validated.events = [
{
functionName: 'First',
http: {
path: 'users/create',
method: 'post',
async: true,
},
},
];
return awsCompileApigEvents.compileMethods().then(() => {
expect(
awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate
.Resources.ApiGatewayMethodUsersCreatePost.Properties.Integration
.RequestParameters['integration.request.header.X-Amz-Invocation-Type']
).to.equal("'Event'");
});
});

it('should add request parameter when integration type is AWS_PROXY and async', () => {
awsCompileApigEvents.validated.events = [
{
functionName: 'First',
http: {
path: 'users/create',
method: 'post',
integration: 'AWS_PROXY',
async: true,
},
},
];
return awsCompileApigEvents.compileMethods().then(() => {
expect(
awsCompileApigEvents.serverless.service.provider.compiledCloudFormationTemplate
.Resources.ApiGatewayMethodUsersCreatePost.Properties.Integration
.RequestParameters['integration.request.header.X-Amz-Invocation-Type']
).to.equal("'Event'");
});
});

it('should set authorizer config for AWS_IAM', () => { it('should set authorizer config for AWS_IAM', () => {
awsCompileApigEvents.validated.events = [ awsCompileApigEvents.validated.events = [
{ {
Expand Down
Expand Up @@ -92,9 +92,8 @@ module.exports = {
IntegrationResponses: this.getIntegrationResponses(http), IntegrationResponses: this.getIntegrationResponses(http),
}); });
} }

if (((type === 'AWS' || type === 'HTTP' || type === 'HTTP_PROXY') &&
if ((type === 'AWS' || type === 'HTTP' || type === 'HTTP_PROXY') && (http.request && !_.isEmpty(http.request.parameters))) || http.async) {
(http.request && !_.isEmpty(http.request.parameters))) {
_.assign(integration, { _.assign(integration, {
RequestParameters: this.getIntegrationRequestParameters(http), RequestParameters: this.getIntegrationRequestParameters(http),
}); });
Expand Down Expand Up @@ -192,6 +191,11 @@ module.exports = {
parameters[`integration.${key.substring('method.'.length)}`] = key; parameters[`integration.${key.substring('method.'.length)}`] = key;
}); });
} }

if (http.async) {
parameters['integration.request.header.X-Amz-Invocation-Type'] = "'Event'";
}

return parameters; return parameters;
}, },


Expand Down
Expand Up @@ -385,6 +385,11 @@ module.exports = {
} }
return normalizedIntegration; return normalizedIntegration;
} }

if (http.async) {
return 'AWS';
}

return 'AWS_PROXY'; return 'AWS_PROXY';
}, },


Expand Down
Expand Up @@ -1563,6 +1563,27 @@ describe('#validate()', () => {
expect(validated.events[0].http.integration).to.equal('MOCK'); expect(validated.events[0].http.integration).to.equal('MOCK');
}); });


it('should support async AWS integration', () => {
awsCompileApigEvents.serverless.service.functions = {
first: {
events: [
{
http: {
method: 'GET',
path: 'users/list',
async: true,
},
},
],
},
};

const validated = awsCompileApigEvents.validate();
expect(validated.events).to.be.an('Array').with.length(1);
expect(validated.events[0].http.integration).to.equal('AWS');
expect(validated.events[0].http.async);
});

it('should show a warning message when using request / response config with LAMBDA-PROXY', () => { it('should show a warning message when using request / response config with LAMBDA-PROXY', () => {
awsCompileApigEvents.serverless.service.functions = { awsCompileApigEvents.serverless.service.functions = {
first: { first: {
Expand Down