diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/handler-snapstart.zip b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/handler-snapstart.zip new file mode 100644 index 0000000000000..eae53ec32da7a Binary files /dev/null and b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/handler-snapstart.zip differ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/asset.a37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5f.zip b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/asset.a37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5f.zip new file mode 100644 index 0000000000000..eae53ec32da7a Binary files /dev/null and b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/asset.a37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5f.zip differ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/aws-cdk-lambda-1.assets.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/aws-cdk-lambda-1.assets.json index 8d61d22779029..a09c57ed5a023 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/aws-cdk-lambda-1.assets.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/aws-cdk-lambda-1.assets.json @@ -1,7 +1,20 @@ { - "version": "21.0.0", + "version": "33.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}" + } + } + }, + "931b3e911bae7029fea07c3a55bc0b5bd8a87b82655f47d331322d9b0245b56f": { "source": { "path": "aws-cdk-lambda-1.template.json", "packaging": "file" @@ -9,7 +22,7 @@ "destinations": { "current_account-current_region": { "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "811c02a1b423ba875c9e41bef2453805f9bd51c7419b5e04664f0e386b7fb4d0.json", + "objectKey": "931b3e911bae7029fea07c3a55bc0b5bd8a87b82655f47d331322d9b0245b56f.json", "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/aws-cdk-lambda-1.template.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/aws-cdk-lambda-1.template.json index 1ca9aa3bc8e44..93570c0aadf3a 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/aws-cdk-lambda-1.template.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/aws-cdk-lambda-1.template.json @@ -58,14 +58,14 @@ "Code": { "ZipFile": "foo" }, + "Description": "version-hash:1786de9fc1bc4cb2fd5b64d612628c6f", + "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "MyLambdaServiceRole4539ECB6", "Arn" ] }, - "Description": "version-hash:1786de9fc1bc4cb2fd5b64d612628c6f", - "Handler": "index.handler", "Runtime": "nodejs14.x" }, "DependsOn": [ @@ -122,13 +122,13 @@ "Type": "AWS::Lambda::Url", "Properties": { "AuthType": "NONE", + "Qualifier": "prod", "TargetFunctionArn": { "Fn::GetAtt": [ "MyLambdaCCE802FB", "Arn" ] - }, - "Qualifier": "prod" + } }, "DependsOn": [ "Alias325C5727" @@ -141,9 +141,66 @@ "FunctionName": { "Ref": "Alias325C5727" }, - "Principal": "*", - "FunctionUrlAuthType": "NONE" + "FunctionUrlAuthType": "NONE", + "Principal": "*" } + }, + "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" + }, + "Description": "version-hash:cb4acf3f2fee0dc7ef3d57cc9e3c231f", + "Handler": "example.Handler::handleRequest", + "Role": { + "Fn::GetAtt": [ + "MySnapStartLambdaServiceRoleE0F04324", + "Arn" + ] + }, + "Runtime": "java11", + "SnapStart": { + "ApplyOn": "PublishedVersions" + } + }, + "DependsOn": [ + "MySnapStartLambdaServiceRoleE0F04324" + ] } }, "Parameters": { diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/cdk.out b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/cdk.out index 8ecc185e9dbee..560dae10d018f 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/cdk.out +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/cdk.out @@ -1 +1 @@ -{"version":"21.0.0"} \ No newline at end of file +{"version":"33.0.0"} \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/integ.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/integ.json index 42adb4c4c7fb2..46bf806e87a36 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/integ.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/integ.json @@ -1,5 +1,5 @@ { - "version": "21.0.0", + "version": "33.0.0", "testCases": { "integ.lambda": { "stacks": [ diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/manifest.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/manifest.json index 47584f5ea926a..8452aef7e9ad7 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/manifest.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/manifest.json @@ -1,12 +1,6 @@ { - "version": "21.0.0", + "version": "33.0.0", "artifacts": { - "Tree": { - "type": "cdk:tree", - "properties": { - "file": "tree.json" - } - }, "aws-cdk-lambda-1.assets": { "type": "cdk:asset-manifest", "properties": { @@ -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}/931b3e911bae7029fea07c3a55bc0b5bd8a87b82655f47d331322d9b0245b56f.json", "requiresBootstrapStackVersion": 6, "bootstrapStackVersionSsmParameter": "/cdk-bootstrap/hnb659fds/version", "additionalDependencies": [ @@ -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" + } } } } \ No newline at end of file diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/tree.json b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/tree.json index 3a46a0555fa18..9bcc9f0f2795b 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/tree.json +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.js.snapshot/tree.json @@ -4,14 +4,6 @@ "id": "App", "path": "", "children": { - "Tree": { - "id": "Tree", - "path": "Tree", - "constructInfo": { - "fqn": "constructs.Construct", - "version": "10.1.85" - } - }, "aws-cdk-lambda-1": { "id": "aws-cdk-lambda-1", "path": "aws-cdk-lambda-1", @@ -24,6 +16,14 @@ "id": "ServiceRole", "path": "aws-cdk-lambda-1/MyLambda/ServiceRole", "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "aws-cdk-lambda-1/MyLambda/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, "Resource": { "id": "Resource", "path": "aws-cdk-lambda-1/MyLambda/ServiceRole/Resource", @@ -59,7 +59,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnRole", + "fqn": "aws-cdk-lib.aws_iam.CfnRole", "version": "0.0.0" } }, @@ -92,19 +92,19 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.CfnPolicy", + "fqn": "aws-cdk-lib.aws_iam.CfnPolicy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Policy", + "fqn": "aws-cdk-lib.aws_iam.Policy", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-iam.Role", + "fqn": "aws-cdk-lib.aws_iam.Role", "version": "0.0.0" } }, @@ -117,18 +117,18 @@ "code": { "zipFile": "foo" }, + "handler": "index.handler", "role": { "Fn::GetAtt": [ "MyLambdaServiceRole4539ECB6", "Arn" ] }, - "handler": "index.handler", "runtime": "nodejs14.x" } }, "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.CfnFunction", + "fqn": "aws-cdk-lib.aws_lambda.CfnFunction", "version": "0.0.0" } }, @@ -152,13 +152,13 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.CfnUrl", + "fqn": "aws-cdk-lib.aws_lambda.CfnUrl", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.FunctionUrl", + "fqn": "aws-cdk-lib.aws_lambda.FunctionUrl", "version": "0.0.0" } }, @@ -178,19 +178,19 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.CfnVersion", + "fqn": "aws-cdk-lib.aws_lambda.CfnVersion", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.Version", + "fqn": "aws-cdk-lib.aws_lambda.Version", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.Function", + "fqn": "aws-cdk-lib.aws_lambda.Function", "version": "0.0.0" } }, @@ -217,7 +217,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.CfnAlias", + "fqn": "aws-cdk-lib.aws_lambda.CfnAlias", "version": "0.0.0" } }, @@ -225,7 +225,7 @@ "id": "ScalingRole", "path": "aws-cdk-lambda-1/Alias/ScalingRole", "constructInfo": { - "fqn": "@aws-cdk/core.Resource", + "fqn": "aws-cdk-lib.Resource", "version": "0.0.0" } }, @@ -243,7 +243,7 @@ } }, "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.CfnPermission", + "fqn": "aws-cdk-lib.aws_lambda.CfnPermission", "version": "0.0.0" } }, @@ -258,23 +258,23 @@ "aws:cdk:cloudformation:type": "AWS::Lambda::Url", "aws:cdk:cloudformation:props": { "authType": "NONE", + "qualifier": "prod", "targetFunctionArn": { "Fn::GetAtt": [ "MyLambdaCCE802FB", "Arn" ] - }, - "qualifier": "prod" + } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.CfnUrl", + "fqn": "aws-cdk-lib.aws_lambda.CfnUrl", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.FunctionUrl", + "fqn": "aws-cdk-lib.aws_lambda.FunctionUrl", "version": "0.0.0" } }, @@ -288,30 +288,177 @@ "functionName": { "Ref": "Alias325C5727" }, - "principal": "*", - "functionUrlAuthType": "NONE" + "functionUrlAuthType": "NONE", + "principal": "*" + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_lambda.CfnPermission", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_lambda.Alias", + "version": "0.0.0" + } + }, + "MySnapStartLambda": { + "id": "MySnapStartLambda", + "path": "aws-cdk-lambda-1/MySnapStartLambda", + "children": { + "ServiceRole": { + "id": "ServiceRole", + "path": "aws-cdk-lambda-1/MySnapStartLambda/ServiceRole", + "children": { + "ImportServiceRole": { + "id": "ImportServiceRole", + "path": "aws-cdk-lambda-1/MySnapStartLambda/ServiceRole/ImportServiceRole", + "constructInfo": { + "fqn": "aws-cdk-lib.Resource", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-cdk-lambda-1/MySnapStartLambda/ServiceRole/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::IAM::Role", + "aws:cdk:cloudformation:props": { + "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" + ] + ] + } + ] + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.CfnRole", + "version": "0.0.0" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_iam.Role", + "version": "0.0.0" + } + }, + "Code": { + "id": "Code", + "path": "aws-cdk-lambda-1/MySnapStartLambda/Code", + "children": { + "Stage": { + "id": "Stage", + "path": "aws-cdk-lambda-1/MySnapStartLambda/Code/Stage", + "constructInfo": { + "fqn": "aws-cdk-lib.AssetStaging", + "version": "0.0.0" + } + }, + "AssetBucket": { + "id": "AssetBucket", + "path": "aws-cdk-lambda-1/MySnapStartLambda/Code/AssetBucket", + "constructInfo": { + "fqn": "aws-cdk-lib.aws_s3.BucketBase", + "version": "0.0.0" + } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.CfnPermission", + "fqn": "aws-cdk-lib.aws_s3_assets.Asset", + "version": "0.0.0" + } + }, + "Resource": { + "id": "Resource", + "path": "aws-cdk-lambda-1/MySnapStartLambda/Resource", + "attributes": { + "aws:cdk:cloudformation:type": "AWS::Lambda::Function", + "aws:cdk:cloudformation:props": { + "code": { + "s3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "s3Key": "a37d3ef54c18e7738fe5dc008504591bd3b1f14c6a09ee91eac6d55f7ca5ba5f.zip" + }, + "handler": "example.Handler::handleRequest", + "role": { + "Fn::GetAtt": [ + "MySnapStartLambdaServiceRoleE0F04324", + "Arn" + ] + }, + "runtime": "java11", + "snapStart": { + "applyOn": "PublishedVersions" + } + } + }, + "constructInfo": { + "fqn": "aws-cdk-lib.aws_lambda.CfnFunction", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/aws-lambda.Alias", + "fqn": "aws-cdk-lib.aws_lambda.Function", + "version": "0.0.0" + } + }, + "BootstrapVersion": { + "id": "BootstrapVersion", + "path": "aws-cdk-lambda-1/BootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnParameter", + "version": "0.0.0" + } + }, + "CheckBootstrapVersion": { + "id": "CheckBootstrapVersion", + "path": "aws-cdk-lambda-1/CheckBootstrapVersion", + "constructInfo": { + "fqn": "aws-cdk-lib.CfnRule", "version": "0.0.0" } } }, "constructInfo": { - "fqn": "@aws-cdk/core.Stack", + "fqn": "aws-cdk-lib.Stack", "version": "0.0.0" } + }, + "Tree": { + "id": "Tree", + "path": "Tree", + "constructInfo": { + "fqn": "constructs.Construct", + "version": "10.2.69" + } } }, "constructInfo": { - "fqn": "@aws-cdk/core.App", + "fqn": "aws-cdk-lib.App", "version": "0.0.0" } } diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.ts index 5e441fd1f6228..ef00f1b706b26 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-lambda/test/integ.lambda.ts @@ -2,6 +2,7 @@ import * as iam from 'aws-cdk-lib/aws-iam'; import * as cdk from 'aws-cdk-lib'; import { LAMBDA_RECOGNIZE_LAYER_VERSION } from 'aws-cdk-lib/cx-api'; import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as path from 'path'; const app = new cdk.App(); @@ -36,4 +37,11 @@ alias.addFunctionUrl({ // to validate the changed function hash. cdk.Aspects.of(stack).add(new lambda.FunctionVersionUpgrade(LAMBDA_RECOGNIZE_LAYER_VERSION)); +new lambda.Function(stack, 'MySnapStartLambda', { + code: lambda.Code.fromAsset(path.join(__dirname, 'handler-snapstart.zip')), + handler: 'example.Handler::handleRequest', + runtime: lambda.Runtime.JAVA_11, + snapStart: lambda.SnapStartConf.ON_PUBLISHED_VERSIONS, +}); + app.synth(); diff --git a/packages/aws-cdk-lib/aws-lambda/README.md b/packages/aws-cdk-lib/aws-lambda/README.md index 30b5839687637..9ca02df90c743 100644 --- a/packages/aws-cdk-lib/aws-lambda/README.md +++ b/packages/aws-cdk-lib/aws-lambda/README.md @@ -902,6 +902,23 @@ const fn = new lambda.Function(this, 'MyFunction', { See [the AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/concurrent-executions.html) managing concurrency. +## Lambda with SnapStart + +SnapStart is currently supported only on Java 11/Java 17 runtime. SnapStart does not support provisioned concurrency, the arm64 architecture, Amazon Elastic File System (Amazon EFS), or ephemeral storage greater than 512 MB. 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(path.join(__dirname, 'handler.zip')), + runtime: lambda.Runtime.JAVA_11, + handler: 'example.Handler::handleRequest', + snapStart: lambda.SnapStartConf.ON_PUBLISHED_VERSIONS, + }); + +const version = fn.currentVersion; +``` + ## AutoScaling You can use Application AutoScaling to automatically configure the provisioned concurrency for your functions. AutoScaling can be set to track utilization or be based on a schedule. To configure AutoScaling on a function alias: diff --git a/packages/aws-cdk-lib/aws-lambda/lib/function.ts b/packages/aws-cdk-lib/aws-lambda/lib/function.ts index 2f53cda366ff8..8b16fcac06697 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/function.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/function.ts @@ -18,6 +18,7 @@ import { LogRetentionRetryOptions } from './log-retention'; import { ParamsAndSecretsLayerVersion } from './params-and-secrets-layers'; import { Runtime, RuntimeFamily } from './runtime'; import { RuntimeManagementMode } from './runtime-management'; +import { SnapStartConf } from './snapstart-config'; import { addAlias } from './util'; import * as cloudwatch from '../../aws-cloudwatch'; import { IProfilingGroup, ProfilingGroup, ComputePlatform } from '../../aws-codeguruprofiler'; @@ -225,6 +226,14 @@ export interface FunctionOptions extends EventInvokeConfigOptions { */ readonly tracing?: Tracing; + /** + * Enable SnapStart for Lambda Function. + * SnapStart is currently supported only for Java 11, 17 runtime + * + * @default - No snapstart + */ + readonly snapStart?: SnapStartConf; + /** * Enable profiling. * @see https://docs.aws.amazon.com/codeguru/latest/profiler-ug/setting-up-lambda.html @@ -832,6 +841,7 @@ export class Function extends FunctionBase { codeSigningConfigArn: props.codeSigningConfig?.codeSigningConfigArn, architectures: this._architecture ? [this._architecture.name] : undefined, runtimeManagementConfig: props.runtimeManagementMode?.runtimeManagementConfig, + snapStart: this.configureSnapStart(props), }); if ((props.tracing !== undefined) || (props.adotInstrumentation !== undefined)) { @@ -1292,6 +1302,38 @@ Environment variables can be marked for removal when used in Lambda@Edge by sett }; } + private configureSnapStart(props: FunctionProps): CfnFunction.SnapStartProperty | undefined { + // return/exit if no snapStart included + if (!props.snapStart) { + return undefined; + } + + // SnapStart does not support arm64 architecture, Amazon Elastic File System (Amazon EFS), or ephemeral storage greater than 512 MB. + // SnapStart doesn't support provisioned concurrency either, but that's configured at the version level, + // so it can't be checked at function set up time + // SnapStart supports the Java 11 and Java 17 (java11 and java17) managed runtimes. + // See https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html + Annotations.of(this).addWarningV2('@aws-cdk/aws-lambda:snapStartRequirePublish', 'SnapStart only support published Lambda versions. Ignore if function already have published versions'); + + if (!props.runtime.supportsSnapStart ) { + throw new Error(`SnapStart currently not supported by runtime ${props.runtime.name}`); + } + + if (props.architecture == Architecture.ARM_64) { + throw new Error('SnapStart is currently not supported on Arm_64'); + } + + if (props.filesystem) { + throw new Error('SnapStart is currently not supported using EFS'); + } + + if (props.ephemeralStorageSize && props.ephemeralStorageSize?.toMebibytes() > 512) { + throw new Error('SnapStart is currently not supported using more than 512 MiB Ephemeral Storage'); + } + + return props.snapStart._render(); + } + private isQueue(deadLetterQueue: sqs.IQueue | sns.ITopic): deadLetterQueue is sqs.IQueue { return (deadLetterQueue).queueArn !== undefined; } diff --git a/packages/aws-cdk-lib/aws-lambda/lib/index.ts b/packages/aws-cdk-lib/aws-lambda/lib/index.ts index 0c8294f3f923f..918c48ffe0ca5 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/index.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/index.ts @@ -25,6 +25,7 @@ export * from './architecture'; export * from './function-url'; export * from './runtime-management'; export * from './params-and-secrets-layers'; +export * from './snapstart-config'; // AWS::Lambda CloudFormation Resources: export * from './lambda.generated'; diff --git a/packages/aws-cdk-lib/aws-lambda/lib/runtime.ts b/packages/aws-cdk-lib/aws-lambda/lib/runtime.ts index 4782d8bfcc045..20029521b52a1 100644 --- a/packages/aws-cdk-lib/aws-lambda/lib/runtime.ts +++ b/packages/aws-cdk-lib/aws-lambda/lib/runtime.ts @@ -24,6 +24,12 @@ export interface LambdaRuntimeProps { * @default false */ readonly supportsCodeGuruProfiling?: boolean; + + /** + * Whether this runtime supports SnapStart. + * @default false + */ + readonly supportsSnapStart?: boolean; } export enum RuntimeFamily { @@ -179,6 +185,7 @@ export class Runtime { */ public static readonly JAVA_11 = new Runtime('java11', RuntimeFamily.JAVA, { supportsCodeGuruProfiling: true, + supportsSnapStart: true, }); /** @@ -186,6 +193,7 @@ export class Runtime { */ public static readonly JAVA_17 = new Runtime('java17', RuntimeFamily.JAVA, { supportsCodeGuruProfiling: true, + supportsSnapStart: true, }); /** @@ -269,6 +277,11 @@ export class Runtime { */ public readonly supportsCodeGuruProfiling: boolean; + /** + * Whether this runtime supports snapstart. + */ + public readonly supportsSnapStart: boolean; + /** * The runtime family. */ @@ -300,6 +313,7 @@ export class Runtime { this.bundlingDockerImage = DockerImage.fromRegistry(imageName); this.bundlingImage = this.bundlingDockerImage; this.supportsCodeGuruProfiling = props.supportsCodeGuruProfiling ?? false; + this.supportsSnapStart = props.supportsSnapStart ?? false; Runtime.ALL.push(this); } diff --git a/packages/aws-cdk-lib/aws-lambda/lib/snapstart-config.ts b/packages/aws-cdk-lib/aws-lambda/lib/snapstart-config.ts new file mode 100644 index 0000000000000..7f7dfdcaa5520 --- /dev/null +++ b/packages/aws-cdk-lib/aws-lambda/lib/snapstart-config.ts @@ -0,0 +1,22 @@ +import { CfnFunction } from './lambda.generated'; + +export abstract class SnapStartConf { + // Enable SnapStart on published lambda versions, this is the only available option available + // see https://docs.aws.amazon.com/lambda/latest/dg/API_SnapStart.html + public static readonly ON_PUBLISHED_VERSIONS = SnapStartConf.applyOn('PublishedVersions'); + + private static applyOn(applyValue: string): SnapStartConf { + return new class extends SnapStartConf { + public _render() { + return { + applyOn: applyValue, + } satisfies CfnFunction.SnapStartProperty; + } + }; + } + + /** + * @internal + */ + public abstract _render(): any; +} \ No newline at end of file diff --git a/packages/aws-cdk-lib/aws-lambda/test/function.test.ts b/packages/aws-cdk-lib/aws-lambda/test/function.test.ts index c3ee0e9a4e6a2..435b535d334bf 100644 --- a/packages/aws-cdk-lib/aws-lambda/test/function.test.ts +++ b/packages/aws-cdk-lib/aws-lambda/test/function.test.ts @@ -2979,6 +2979,114 @@ describe('function', () => { }); }); + describe('SnapStart', () => { + test('set SnapStart to desired value', () => { + const stack = new cdk.Stack(); + new lambda.CfnFunction(stack, 'MyLambda', { + code: { + zipFile: 'java11-test-function.zip', + }, + functionName: 'MyCDK-SnapStart-Function', + handler: 'example.Handler::handleRequest', + role: 'testRole', + runtime: 'java11', + snapStart: { applyOn: 'PublishedVersions' }, + }); + + Template.fromStack(stack).hasResource('AWS::Lambda::Function', { + Properties: + { + Code: { ZipFile: 'java11-test-function.zip' }, + Handler: 'example.Handler::handleRequest', + Runtime: 'java11', + SnapStart: { + ApplyOn: 'PublishedVersions', + }, + }, + }); + }); + + test('function using SnapStart', () => { + const stack = new cdk.Stack(); + //WHEN + new lambda.Function(stack, 'MyLambda', { + code: lambda.Code.fromAsset(path.join(__dirname, 'handler.zip')), + handler: 'example.Handler::handleRequest', + runtime: lambda.Runtime.JAVA_11, + snapStart: lambda.SnapStartConf.ON_PUBLISHED_VERSIONS, + }); + + //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: lambda.SnapStartConf.ON_PUBLISHED_VERSIONS, + })).toThrowError('SnapStart currently not supported by runtime nodejs14.x'); + }); + + test('arm64 validation for snapStart', () => { + const stack = new cdk.Stack(); + + expect(() => new lambda.Function(stack, 'MyLambda', { + code: lambda.Code.fromAsset(path.join(__dirname, 'handler.zip')), + handler: 'example.Handler::handleRequest', + runtime: lambda.Runtime.JAVA_11, + architecture: lambda.Architecture.ARM_64, + snapStart: lambda.SnapStartConf.ON_PUBLISHED_VERSIONS, + })).toThrowError('SnapStart is currently not supported on Arm_64'); + }); + + test('EFS validation for snapStart', () => { + const stack = new cdk.Stack(); + const vpc = new ec2.Vpc(stack, 'Vpc', { + maxAzs: 3, + natGateways: 1, + }); + + const fs = new efs.FileSystem(stack, 'Efs', { + vpc, + }); + const accessPoint = fs.addAccessPoint('AccessPoint'); + + expect(() => new lambda.Function(stack, 'MyLambda', { + vpc, + code: lambda.Code.fromAsset(path.join(__dirname, 'handler.zip')), + handler: 'example.Handler::handleRequest', + runtime: lambda.Runtime.JAVA_11, + filesystem: lambda.FileSystem.fromEfsAccessPoint(accessPoint, '/mnt/msg'), + snapStart: lambda.SnapStartConf.ON_PUBLISHED_VERSIONS, + })).toThrowError('SnapStart is currently not supported using EFS'); + }); + + test('arm64 validation for snapStart', () => { + const stack = new cdk.Stack(); + + expect(() => new lambda.Function(stack, 'MyLambda', { + code: lambda.Code.fromAsset(path.join(__dirname, 'handler.zip')), + handler: 'example.Handler::handleRequest', + runtime: lambda.Runtime.JAVA_11, + ephemeralStorageSize: Size.mebibytes(1024), + snapStart: lambda.SnapStartConf.ON_PUBLISHED_VERSIONS, + })).toThrowError('SnapStart is currently not supported using more than 512 MiB Ephemeral Storage'); + }); + }); + test('called twice for the same service principal but with different conditions', () => { // GIVEN const stack = new cdk.Stack(); @@ -3220,32 +3328,6 @@ test('function using a reserved environment variable', () => { })).toThrow(/AWS_REGION environment variable is reserved/); }); -test('set SnapStart to desired value', () => { - const stack = new cdk.Stack(); - new lambda.CfnFunction(stack, 'MyLambda', { - code: { - zipFile: 'java11-test-function.zip', - }, - functionName: 'MyCDK-SnapStart-Function', - handler: 'example.Handler::handleRequest', - role: 'testRole', - runtime: 'java11', - snapStart: { applyOn: 'PublishedVersions' }, - }); - - Template.fromStack(stack).hasResource('AWS::Lambda::Function', { - Properties: - { - Code: { ZipFile: 'java11-test-function.zip' }, - Handler: 'example.Handler::handleRequest', - Runtime: 'java11', - SnapStart: { - ApplyOn: 'PublishedVersions', - }, - }, - }); -}); - test('test 2.87.0 version hash stability', () => { // GIVEN const app = new cdk.App({