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

feat(lambda): support for Lambda SnapStart #23196

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions packages/@aws-cdk/aws-lambda/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -772,6 +772,23 @@ CodeGuru profiling is supported for all Java runtimes and Python3.6+ runtimes.
See [the AWS documentation](https://docs.aws.amazon.com/codeguru/latest/profiler-ug/setting-up-lambda.html)
to learn more about AWS Lambda's Profiling support.

## Lambda with SnapStart

SnapStart is currently supported only on Java 11 runtime. After you enable Lambda SnapStart for a particular Lambda function, publishing a new version of the function will trigger an optimization process.

See [the AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html) to learn more about AWS Lambda SnapStart

```ts
const fn = new lambda.Function(this, 'MyFunction', {
code: lambda.Code.fromAsset('handler.zip'),
runtime: lambda.Runtime.JAVA_11,
handler: 'example.Handler::handleRequest',
snapStart: true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I concur with @TheRealAmazonKendra. There's too many restrictions on the lambda to put this as a constructor prop (from https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html):

SnapStart supports the Java 11 runtime.

SnapStart does not support provisioned concurrency, the arm64 architecture, the Lambda Extensions API, Amazon Elastic File System (Amazon EFS), AWS X-Ray, or ephemeral storage greater than 512 MB.

it's good that you added error checking for the Java11 runtime case, but all of these other restrictions must also be checked at synth time. This bloats the constructor with unnecessary checks that will eventually be removed when Lambda rolls this out to more function types.

Because we need those type checks today, and we will one day have to deprecate them, I agree with @TheRealAmazonKendra's suggestion to make this a new method (maybe enableSnapStart()?) on the Function class that will do all of this error checking in one place.

});

const version = fn.currentVersion;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Good to know fn.currentVersion will actually create a new version if no existing version.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is actually another great reason for this to not be a prop. For this to be a prop, you should be able to create a brand new Lambda function with this prop enabled, and the deployment should succeed.

This won't work though, because to enable start, a version has to already be published, and that needs an existing function. Normally, CFN can create the lambda function and the version at once since it can figure out the dependency, but this is a circular dependency; the Version depends on the Function, but the Function also depends on the Version because snap start is a property on the function itself.

(unless of course CFN figures this out for us, which I will check manually later, but it's not clear right now).

So, in summary: we need a method enableSnapStart() that does this error checking and clearly documents the restrictions, including the restriction that a lambda function must already have been deployed to enable this (assuming this restriction actually exists, again I'll verify this later).

```

## Lambda with Reserved Concurrent Executions

```ts
Expand Down
14 changes: 13 additions & 1 deletion packages/@aws-cdk/aws-lambda/lib/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,14 @@ export interface FunctionOptions extends EventInvokeConfigOptions {
readonly tracing?: Tracing;

/**
* Enable profiling.
* Enable SnapStart for Lambda Function.
* SnapStart is currently supported only for Java 11 runtime
*
* @default false
*/
readonly snapStart?: boolean;

/** Enable profiling.
* @see https://docs.aws.amazon.com/codeguru/latest/profiler-ug/setting-up-lambda.html
*
* @default - No profiling.
Expand Down Expand Up @@ -769,6 +776,10 @@ export class Function extends FunctionBase {
throw new Error(`Ephemeral storage size must be between 512 and 10240 MB, received ${props.ephemeralStorageSize}.`);
}

if (props.snapStart && props.runtime != Runtime.JAVA_11) {
throw new Error('SnapStart is currently supported only Java 11 runtime');
}

const resource: CfnFunction = new CfnFunction(this, 'Resource', {
functionName: this.physicalName,
description: props.description,
Expand Down Expand Up @@ -805,6 +816,7 @@ export class Function extends FunctionBase {
fileSystemConfigs,
codeSigningConfigArn: props.codeSigningConfig?.codeSigningConfigArn,
architectures: this._architecture ? [this._architecture.name] : undefined,
snapStart: props.snapStart ? { applyOn: 'PublishedVersions' } : undefined,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love the clean design but I am also wary if they will support all versions including the $latest one. But I agree we keep the simple design as is.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we check and throws error if the runtime is not JAVA_11 and snapStart is enabled?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we should. Resource creation on AWS throws an error as there is a validation that they do. So it makes sense to add the validation to CDK build. Added validation, and provided unit test for the same.

});

resource.node.addDependency(this.role);
Expand Down
34 changes: 34 additions & 0 deletions packages/@aws-cdk/aws-lambda/test/function.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3152,6 +3152,40 @@ test('set SnapStart to desired value', () => {
});
});

test('function using SnapStart', () => {
const stack = new cdk.Stack();
//WHEN
new lambda.Function(stack, 'MyLambda', {
code: lambda.Code.fromAsset('test/handler.zip'),
handler: 'example.Handler::handleRequest',
runtime: lambda.Runtime.JAVA_11,
snapStart: true,
});

//THEN
Template.fromStack(stack).hasResource('AWS::Lambda::Function', {
Properties:
{
Handler: 'example.Handler::handleRequest',
Runtime: 'java11',
SnapStart: {
ApplyOn: 'PublishedVersions',
},
},
});
});

test('runtime validation for snapStart', () => {
const stack = new cdk.Stack();

expect(() => new lambda.Function(stack, 'MyLambda', {
code: new lambda.InlineCode('foo'),
handler: 'bar',
runtime: lambda.Runtime.NODEJS_14_X,
snapStart: true,
})).toThrowError('SnapStart is currently supported only Java 11 runtime');
});

function newTestLambda(scope: constructs.Construct) {
return new lambda.Function(scope, 'MyLambda', {
code: new lambda.InlineCode('foo'),
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
{
"version": "21.0.0",
"files": {
"811c02a1b423ba875c9e41bef2453805f9bd51c7419b5e04664f0e386b7fb4d0": {
"a37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5f": {
"source": {
"path": "asset.a37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5f.zip",
"packaging": "file"
},
"destinations": {
"current_account-current_region": {
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
"objectKey": "a37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5f.zip",
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
}
}
},
"98d7e855b296d744440daffb6e5133987604d7362b92494afa1f9e3190b7b9f6": {
"source": {
"path": "aws-cdk-lambda-1.template.json",
"packaging": "file"
},
"destinations": {
"current_account-current_region": {
"bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}",
"objectKey": "811c02a1b423ba875c9e41bef2453805f9bd51c7419b5e04664f0e386b7fb4d0.json",
"objectKey": "98d7e855b296d744440daffb6e5133987604d7362b92494afa1f9e3190b7b9f6.json",
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,63 @@
"Principal": "*",
"FunctionUrlAuthType": "NONE"
}
},
"MySnapStartLambdaServiceRoleE0F04324": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
}
}
],
"Version": "2012-10-17"
},
"ManagedPolicyArns": [
{
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
]
]
}
]
}
},
"MySnapStartLambda8F562E6E": {
"Type": "AWS::Lambda::Function",
"Properties": {
"Code": {
"S3Bucket": {
"Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}"
},
"S3Key": "a37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5f.zip"
},
"Role": {
"Fn::GetAtt": [
"MySnapStartLambdaServiceRoleE0F04324",
"Arn"
]
},
"Description": "version-hash:cb4acf3f2fee0dc7ef3d57cc9e3c231f",
"Handler": "example.Handler::handleRequest",
"Runtime": "java11",
"SnapStart": {
"ApplyOn": "PublishedVersions"
}
},
"DependsOn": [
"MySnapStartLambdaServiceRoleE0F04324"
]
}
},
"Parameters": {
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"version":"21.0.0"}
{"version":"22.0.0"}
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
{
"version": "21.0.0",
"artifacts": {
"Tree": {
"type": "cdk:tree",
"properties": {
"file": "tree.json"
}
},
"aws-cdk-lambda-1.assets": {
"type": "cdk:asset-manifest",
"properties": {
Expand All @@ -23,7 +17,7 @@
"validateOnSynth": false,
"assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-deploy-role-${AWS::AccountId}-${AWS::Region}",
"cloudFormationExecutionRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-cfn-exec-role-${AWS::AccountId}-${AWS::Region}",
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/811c02a1b423ba875c9e41bef2453805f9bd51c7419b5e04664f0e386b7fb4d0.json",
"stackTemplateAssetObjectUrl": "s3://cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}/98d7e855b296d744440daffb6e5133987604d7362b92494afa1f9e3190b7b9f6.json",
"requiresBootstrapStackVersion": 6,
"bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version",
"additionalDependencies": [
Expand Down Expand Up @@ -93,29 +87,38 @@
"data": "Aliasinvokefunctionurl4CA9917B"
}
],
"/aws-cdk-lambda-1/BootstrapVersion": [
"/aws-cdk-lambda-1/MySnapStartLambda/ServiceRole/Resource": [
{
"type": "aws:cdk:logicalId",
"data": "BootstrapVersion"
"data": "MySnapStartLambdaServiceRoleE0F04324"
}
],
"/aws-cdk-lambda-1/CheckBootstrapVersion": [
"/aws-cdk-lambda-1/MySnapStartLambda/Resource": [
{
"type": "aws:cdk:logicalId",
"data": "CheckBootstrapVersion"
"data": "MySnapStartLambda8F562E6E"
}
],
"/aws-cdk-lambda-1/BootstrapVersion": [
{
"type": "aws:cdk:logicalId",
"data": "BootstrapVersion"
}
],
"MyLambdaCurrentVersionE7A382CC1786de9fc1bc4cb2fd5b64d612628c6f": [
"/aws-cdk-lambda-1/CheckBootstrapVersion": [
{
"type": "aws:cdk:logicalId",
"data": "MyLambdaCurrentVersionE7A382CC1786de9fc1bc4cb2fd5b64d612628c6f",
"trace": [
"!!DESTRUCTIVE_CHANGES: WILL_DESTROY"
]
"data": "CheckBootstrapVersion"
}
]
},
"displayName": "aws-cdk-lambda-1"
},
"Tree": {
"type": "cdk:tree",
"properties": {
"file": "tree.json"
}
}
}
}
Loading