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

Update AWS Limits on Lambda@Edge #6922

Merged
merged 2 commits into from Nov 5, 2019
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

@@ -33,6 +33,8 @@ Lambda@Edge has four options when the Lambda function is triggered

**IMPORTANT:** Due to current [Lambda@Edge limitations](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-edge-delete-replicas.html) it's necessary to set the `DeletionPolicy` to `Retain` for AWS Lambda functions which use the `cloudFront` event. The Serverless Framework will do this automatically for you. However bear in mind that **you have to delete those AWS Lambda functions manually** once you've removed the service via `serverless remove`.

**MEMORY AND TIMEOUT LIMITS:** According to [AWS Limits on Lambda@Edge](https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-limits.html#limits-lambda-at-edge) the limits for viewer-request and viewer-response are 128MB memory and 5 seconds timeout and for origin-request and origin-response are 3008MB memory and 30 seconds timeout.

## Simple event definition

This will enable your Lambda@Edge function to be called by a CloudFront.
@@ -5,11 +5,21 @@ const url = require('url');
const chalk = require('chalk');
const { ServerlessError } = require('../../../../../../classes/Error');

const originLimits = { maxTimeout: 30, maxMemorySize: 3008 };
const viewerLimits = { maxTimeout: 5, maxMemorySize: 128 };

class AwsCompileCloudFrontEvents {
constructor(serverless, options) {
this.serverless = serverless;
this.options = options;
this.provider = this.serverless.getProvider('aws');
this.lambdaEdgeLimits = {
'origin-request': originLimits,
'origin-response': originLimits,
'viewer-request': viewerLimits,
'viewer-response': viewerLimits,
'default': viewerLimits,
};
this.hooks = {
'package:initialize': this.validate.bind(this),
'before:package:compileFunctions': this.prepareFunctions.bind(this),
@@ -41,18 +51,21 @@ class AwsCompileCloudFrontEvents {
validate() {
this.serverless.service.getAllFunctions().forEach(functionName => {
const functionObj = this.serverless.service.getFunction(functionName);
if (functionObj.events.find(event => event.cloudFront)) {
if (functionObj.memorySize && functionObj.memorySize > 128) {
functionObj.events.forEach(({ cloudFront }) => {
if (!cloudFront) return;
const { eventType = 'default' } = cloudFront;
const { maxMemorySize, maxTimeout } = this.lambdaEdgeLimits[eventType];
if (functionObj.memorySize && functionObj.memorySize > maxMemorySize) {
throw new Error(
`"${functionName}" memorySize is greater than 128 which is not supported by Lambda@Edge functions`
`"${functionName}" memorySize is greater than ${maxMemorySize} which is not supported by Lambda@Edge functions of type "${eventType}"`
);
}
if (functionObj.timeout && functionObj.timeout > 5) {
if (functionObj.timeout && functionObj.timeout > maxTimeout) {
throw new Error(
`"${functionName}" timeout is greater than 5 which is not supported by Lambda@Edge functions`
`"${functionName}" timeout is greater than ${maxTimeout} which is not supported by Lambda@Edge functions of type "${eventType}"`
);
}
}
});
});
}

@@ -126,7 +126,7 @@ describe('AwsCompileCloudFrontEvents', () => {
});

describe('#validate()', () => {
it('should throw if memorySize is greater than 128', () => {
it('should throw if memorySize is greater than 128 for viewer-request or viewer-response functions', () => {
awsCompileCloudFrontEvents.serverless.service.functions = {
first: {
memorySize: 129,
@@ -144,9 +144,27 @@ describe('AwsCompileCloudFrontEvents', () => {
expect(() => {
awsCompileCloudFrontEvents.validate();
}).to.throw(Error, 'greater than 128');

awsCompileCloudFrontEvents.serverless.service.functions = {
first: {
memorySize: 129,
events: [
{
cloudFront: {
eventType: 'viewer-response',
origin: 's3://bucketname.s3.amazonaws.com/files',
},
},
],
},
};

expect(() => {
awsCompileCloudFrontEvents.validate();
}).to.throw(Error, 'greater than 128');
});

it('should throw if timeout is greater than 5', () => {
it('should throw if timeout is greater than 5 for viewer-request or viewer response functions', () => {
awsCompileCloudFrontEvents.serverless.service.functions = {
first: {
timeout: 6,
@@ -164,6 +182,98 @@ describe('AwsCompileCloudFrontEvents', () => {
expect(() => {
awsCompileCloudFrontEvents.validate();
}).to.throw(Error, 'greater than 5');
awsCompileCloudFrontEvents.serverless.service.functions = {
first: {
timeout: 6,
events: [
{
cloudFront: {
eventType: 'viewer-response',
origin: 's3://bucketname.s3.amazonaws.com/files',
},
},
],
},
};

expect(() => {
awsCompileCloudFrontEvents.validate();
}).to.throw(Error, 'greater than 5');
});

it('should throw if memorySize is greater than 3008 for origin-request or origin-response functions', () => {
awsCompileCloudFrontEvents.serverless.service.functions = {
first: {
memorySize: 3009,
events: [
{
cloudFront: {
eventType: 'origin-request',
origin: 's3://bucketname.s3.amazonaws.com/files',
},
},
],
},
};

expect(() => {
awsCompileCloudFrontEvents.validate();
}).to.throw(Error, 'greater than 3008');

awsCompileCloudFrontEvents.serverless.service.functions = {
first: {
memorySize: 3009,
events: [
{
cloudFront: {
eventType: 'origin-response',
origin: 's3://bucketname.s3.amazonaws.com/files',
},
},
],
},
};

expect(() => {
awsCompileCloudFrontEvents.validate();
}).to.throw(Error, 'greater than 3008');
});

it('should throw if timeout is greater than 30 for origin-request or origin response functions', () => {
awsCompileCloudFrontEvents.serverless.service.functions = {
first: {
timeout: 31,
events: [
{
cloudFront: {
eventType: 'origin-request',
origin: 's3://bucketname.s3.amazonaws.com/files',
},
},
],
},
};

expect(() => {
awsCompileCloudFrontEvents.validate();
}).to.throw(Error, 'greater than 30');
awsCompileCloudFrontEvents.serverless.service.functions = {
first: {
timeout: 31,
events: [
{
cloudFront: {
eventType: 'origin-response',
origin: 's3://bucketname.s3.amazonaws.com/files',
},
},
],
},
};

expect(() => {
awsCompileCloudFrontEvents.validate();
}).to.throw(Error, 'greater than 30');
});
});

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.