From aea2d4f1fb61952a8397fb9cbfbb90cf61b6aeeb Mon Sep 17 00:00:00 2001 From: Yukinobu Mine <14157373+Yukinobu-Mine@users.noreply.github.com> Date: Fri, 29 Nov 2024 16:43:05 +0900 Subject: [PATCH] Fix: Lambda SnapStart for Python functions doesn't supported in some regions. (#618) * Fix: Lambda SnapStart for Python functions doesn't supported in some regions. - Provide the option to disable Lambda SnapStart. - `enableLambdaSnapStart` in cdk.json * Disable Lambda SnapStart on super-easy deployment. --- README.md | 10 ++++++++++ bin.sh | 3 +++ cdk/bin/bedrock-chat.ts | 2 ++ cdk/cdk.json | 3 ++- cdk/lib/bedrock-chat-stack.ts | 3 +++ cdk/lib/constructs/api.ts | 9 ++++----- cdk/lib/constructs/websocket.ts | 3 ++- cdk/test/cdk.test.ts | 3 +++ deploy.yml | 8 +++++++- docs/README_ja.md | 10 ++++++++++ 10 files changed, 46 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index a499900fc..4664af901 100644 --- a/README.md +++ b/README.md @@ -90,6 +90,7 @@ chmod +x bin.sh You can specify the following parameters during deployment to enhance security and customization: - **--disable-self-register**: Disable self-registration (default: enabled). If this flag is set, you will need to create all users on cognito and it will not allow users to self register their accounts. +- **--enable-lambda-snapstart**: Enable [Lambda SnapStart](https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html) (default: disabled). If this flag is set, improves cold start times for Lambda functions, providing faster response times for better user experience. - **--ipv4-ranges**: Comma-separated list of allowed IPv4 ranges. (default: allow all ipv4 addresses) - **--ipv6-ranges**: Comma-separated list of allowed IPv6 ranges. (default: allow all ipv6 addresses) - **--disable-ipv6**: Disable connections over IPv6. (default: enabled) @@ -176,6 +177,7 @@ cdk bootstrap aws:///us-east-1 - `bedrockRegion`: Region where Bedrock is available. **NOTE: Bedrock does NOT support all regions for now.** - `allowedIpV4AddressRanges`, `allowedIpV6AddressRanges`: Allowed IP Address range. + - `enableLambdaSnapStart`: Defaults to true. Set to false if deploying to a [region that doesn't support Lambda SnapStart for Python functions](https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html#snapstart-supported-regions). - Deploy this sample project @@ -288,6 +290,14 @@ This is an account/region-level setting, affecting the entire application rather "enableBedrockCrossRegionInference": true ``` +### Lambda SnapStart + +[Lambda SnapStart](https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html) improves cold start times for Lambda functions, providing faster response times for better user experience. On the other hand, for Python functions, there is a [charge depending on cache size](https://aws.amazon.com/lambda/pricing/#SnapStart_Pricing) and [not available in some regions](https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html#snapstart-supported-regions) currently. To disable SnapStart, edit `cdk.json`. + +```json +"enableLambdaSnapStart": false +``` + ### Local Development See [LOCAL DEVELOPMENT](./docs/LOCAL_DEVELOPMENT.md). diff --git a/bin.sh b/bin.sh index dbbd44ffd..7eef7ba6e 100755 --- a/bin.sh +++ b/bin.sh @@ -35,6 +35,7 @@ done # Default parameters ALLOW_SELF_REGISTER="true" +ENABLE_LAMBDA_SNAPSTART="false" IPV4_RANGES="" IPV6_RANGES="" DISABLE_IPV6="false" @@ -46,6 +47,7 @@ VERSION="v2" while [[ "$#" -gt 0 ]]; do case $1 in --disable-self-register) ALLOW_SELF_REGISTER="false" ;; + --enable-lambda-snapstart) ENABLE_LAMBDA_SNAPSTART="true" ;; --disable-ipv6) DISABLE_IPV6="true" ;; --ipv4-ranges) IPV4_RANGES="$2"; shift ;; --ipv6-ranges) IPV6_RANGES="$2"; shift ;; @@ -74,6 +76,7 @@ aws cloudformation deploy \ --capabilities CAPABILITY_IAM \ --parameter-overrides \ AllowSelfRegister=$ALLOW_SELF_REGISTER \ + EnableLambdaSnapStart=$ENABLE_LAMBDA_SNAPSTART \ DisableIpv6=$DISABLE_IPV6 \ Ipv4Ranges="$IPV4_RANGES" \ Ipv6Ranges="$IPV6_RANGES" \ diff --git a/cdk/bin/bedrock-chat.ts b/cdk/bin/bedrock-chat.ts index 69a3fb42a..5f0b26efc 100644 --- a/cdk/bin/bedrock-chat.ts +++ b/cdk/bin/bedrock-chat.ts @@ -43,6 +43,7 @@ const USE_STAND_BY_REPLICAS: boolean = const ENABLE_BEDROCK_CROSS_REGION_INFERENCE: boolean = app.node.tryGetContext( "enableBedrockCrossRegionInference" ); +const ENABLE_LAMBDA_SNAPSTART: boolean = app.node.tryGetContext("enableLambdaSnapStart"); // WAF for frontend // 2023/9: Currently, the WAF for CloudFront needs to be created in the North America region (us-east-1), so the stacks are separated @@ -94,6 +95,7 @@ const chat = new BedrockChatStack(app, `BedrockChatStack`, { documentBucket: bedrockRegionResources.documentBucket, useStandbyReplicas: USE_STAND_BY_REPLICAS, enableBedrockCrossRegionInference: ENABLE_BEDROCK_CROSS_REGION_INFERENCE, + enableLambdaSnapStart: ENABLE_LAMBDA_SNAPSTART, }); chat.addDependency(waf); chat.addDependency(bedrockRegionResources); diff --git a/cdk/cdk.json b/cdk/cdk.json index 60b8ccdaa..8983523ea 100644 --- a/cdk/cdk.json +++ b/cdk/cdk.json @@ -69,6 +69,7 @@ "8000:0000:0000:0000:0000:0000:0000:0000/1" ], "enableRagReplicas": true, - "enableBedrockCrossRegionInference": true + "enableBedrockCrossRegionInference": true, + "enableLambdaSnapStart": true } } diff --git a/cdk/lib/bedrock-chat-stack.ts b/cdk/lib/bedrock-chat-stack.ts index 86c122959..0c01b54d7 100644 --- a/cdk/lib/bedrock-chat-stack.ts +++ b/cdk/lib/bedrock-chat-stack.ts @@ -39,6 +39,7 @@ export interface BedrockChatStackProps extends StackProps { readonly documentBucket: Bucket; readonly useStandbyReplicas: boolean; readonly enableBedrockCrossRegionInference: boolean; + readonly enableLambdaSnapStart: boolean; } export class BedrockChatStack extends cdk.Stack { @@ -165,6 +166,7 @@ export class BedrockChatStack extends cdk.Stack { usageAnalysis, largeMessageBucket, enableMistral: props.enableMistral, + enableLambdaSnapStart: props.enableLambdaSnapStart, }); props.documentBucket.grantReadWrite(backendApi.handler); @@ -181,6 +183,7 @@ export class BedrockChatStack extends cdk.Stack { enableMistral: props.enableMistral, enableBedrockCrossRegionInference: props.enableBedrockCrossRegionInference, + enableLambdaSnapStart: props.enableLambdaSnapStart, }); frontend.buildViteApp({ backendApiEndpoint: backendApi.api.apiEndpoint, diff --git a/cdk/lib/constructs/api.ts b/cdk/lib/constructs/api.ts index 1cc2724da..54dcc77c2 100644 --- a/cdk/lib/constructs/api.ts +++ b/cdk/lib/constructs/api.ts @@ -4,9 +4,7 @@ import { ITable } from "aws-cdk-lib/aws-dynamodb"; import { HttpLambdaIntegration } from "aws-cdk-lib/aws-apigatewayv2-integrations"; import { HttpUserPoolAuthorizer } from "aws-cdk-lib/aws-apigatewayv2-authorizers"; import { - Code, - DockerImageCode, - DockerImageFunction, + Architecture, IFunction, LayerVersion, Runtime, @@ -18,7 +16,6 @@ import { HttpMethod, } from "aws-cdk-lib/aws-apigatewayv2"; import { Auth } from "./auth"; -import { Platform } from "aws-cdk-lib/aws-ecr-assets"; import { Stack } from "aws-cdk-lib"; import * as iam from "aws-cdk-lib/aws-iam"; import * as logs from "aws-cdk-lib/aws-logs"; @@ -41,6 +38,7 @@ export interface ApiProps { readonly bedrockCustomBotProject: codebuild.IProject; readonly usageAnalysis?: UsageAnalysis; readonly enableMistral: boolean; + readonly enableLambdaSnapStart: boolean; } export class Api extends Construct { @@ -184,6 +182,7 @@ export class Api extends Construct { buildArgs: { POETRY_VERSION: "1.8.3" }, }, runtime: Runtime.PYTHON_3_12, + architecture: Architecture.X86_64, memorySize: 1024, timeout: Duration.minutes(15), environment: { @@ -212,7 +211,7 @@ export class Api extends Construct { }, role: handlerRole, logRetention: logs.RetentionDays.THREE_MONTHS, - snapStart: SnapStartConf.ON_PUBLISHED_VERSIONS, + snapStart: props.enableLambdaSnapStart ? SnapStartConf.ON_PUBLISHED_VERSIONS : undefined, layers: [ LayerVersion.fromLayerVersionArn( this, diff --git a/cdk/lib/constructs/websocket.ts b/cdk/lib/constructs/websocket.ts index d883f94e7..bfb3d641c 100644 --- a/cdk/lib/constructs/websocket.ts +++ b/cdk/lib/constructs/websocket.ts @@ -29,6 +29,7 @@ export interface WebSocketProps { readonly accessLogBucket?: s3.Bucket; readonly enableMistral: boolean; readonly enableBedrockCrossRegionInference: boolean; + readonly enableLambdaSnapStart: boolean; } export class WebSocket extends Construct { @@ -110,7 +111,7 @@ export class WebSocket extends Construct { props.enableBedrockCrossRegionInference.toString(), }, role: handlerRole, - snapStart: SnapStartConf.ON_PUBLISHED_VERSIONS, + snapStart: props.enableLambdaSnapStart ? SnapStartConf.ON_PUBLISHED_VERSIONS : undefined, logRetention: logs.RetentionDays.THREE_MONTHS, }); diff --git a/cdk/test/cdk.test.ts b/cdk/test/cdk.test.ts index 1361bc23b..67641d5dd 100644 --- a/cdk/test/cdk.test.ts +++ b/cdk/test/cdk.test.ts @@ -55,6 +55,7 @@ describe("Bedrock Chat Stack Test", () => { documentBucket: bedrockRegionResourcesStack.documentBucket, useStandbyReplicas: false, enableBedrockCrossRegionInference: false, + enableLambdaSnapStart: true, } ); const hasGoogleProviderTemplate = Template.fromStack( @@ -125,6 +126,7 @@ describe("Bedrock Chat Stack Test", () => { documentBucket: bedrockRegionResourcesStack.documentBucket, useStandbyReplicas: false, enableBedrockCrossRegionInference: false, + enableLambdaSnapStart: true, } ); const hasOidcProviderTemplate = Template.fromStack(hasOidcProviderStack); @@ -185,6 +187,7 @@ describe("Bedrock Chat Stack Test", () => { documentBucket: bedrockRegionResourcesStack.documentBucket, useStandbyReplicas: false, enableBedrockCrossRegionInference: false, + enableLambdaSnapStart: true, }); const template = Template.fromStack(stack); diff --git a/deploy.yml b/deploy.yml index 39c4fdeab..ca9122ab8 100644 --- a/deploy.yml +++ b/deploy.yml @@ -5,6 +5,9 @@ Parameters: AllowSelfRegister: Type: String Default: "true" + EnableLambdaSnapStart: + Type: String + Default: "false" Ipv4Ranges: Type: String Default: '["0.0.0.0/1","128.0.0.0/1"]' # Set default values based on current config @@ -113,6 +116,8 @@ Resources: EnvironmentVariables: - Name: ALLOW_SELF_REGISTER Value: !Ref AllowSelfRegister + - Name: ENABLE_LAMBDA_SNAPSTART + Value: !Ref EnableLambdaSnapStart - Name: IPV4_RANGES Value: !Ref Ipv4Ranges - Name: IPV6_RANGES @@ -148,7 +153,8 @@ Resources: "echo 'Build phase...'", "git clone --branch $VERSION https://github.com/aws-samples/bedrock-claude-chat.git", "cd bedrock-claude-chat", - "if [ \"$ALLOW_SELF_REGISTER\" = \"false\" ]; then sed -i 's/\"selfSignUpEnabled\": true,/\"selfSignUpEnabled\": false,/' cdk/cdk.json; fi", + "if [ \"$ALLOW_SELF_REGISTER\" = \"false\" ]; then sed -i 's/\"selfSignUpEnabled\": true/\"selfSignUpEnabled\": false/' cdk/cdk.json; fi", + "if [ \"$ENABLE_LAMBDA_SNAPSTART\" = \"false\" ]; then sed -i 's/\"enableLambdaSnapStart\": true/\"enableLambdaSnapStart\": false/' cdk/cdk.json; fi", "if [ ! -z \"$IPV4_RANGES\" ]; then jq --arg ipv4 \"$IPV4_RANGES\" '.context.allowedIpV4AddressRanges = ($ipv4 | split(\",\"))' cdk/cdk.json > temp.json && mv temp.json cdk/cdk.json; fi", "if [ \"$DISABLE_IPV6\" = \"true\" ]; then jq '.context.allowedIpV6AddressRanges = []' cdk/cdk.json > temp.json && mv temp.json cdk/cdk.json; elif [ ! -z \"$IPV6_RANGES\" ]; then jq --arg ipv6 \"$IPV6_RANGES\" '.context.allowedIpV6AddressRanges = ($ipv6 | split(\",\"))' cdk/cdk.json > temp.json && mv temp.json cdk/cdk.json; fi", "if [ ! -z \"$ALLOWED_SIGN_UP_EMAIL_DOMAINS\" ]; then jq --arg domains \"$ALLOWED_SIGN_UP_EMAIL_DOMAINS\" '.context.allowedSignUpEmailDomains = ($domains | split(\",\"))' cdk/cdk.json > temp.json && mv temp.json cdk/cdk.json; fi", diff --git a/docs/README_ja.md b/docs/README_ja.md index abd408331..b045bbccf 100644 --- a/docs/README_ja.md +++ b/docs/README_ja.md @@ -60,6 +60,7 @@ chmod +x bin.sh デプロイ時に以下のパラメータを指定することで、セキュリティとカスタマイズを強化できます。 - **--disable-self-register**: セルフ登録を無効にします(デフォルト: 有効)。このフラグを設定すると、Cognito 上で全てのユーザーを作成する必要があり、ユーザーが自分でアカウントを登録することはできなくなります。 +- **--enable-lambda-snapstart**: [Lambda SnapStart](https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html) を有効化します (デフォルト: 無効)。 このフラグを設定すると、Lambda 関数のコールドスタート時間を短縮し、レスポンスタイムの改善によってユーザー体験を向上させます。 - **--ipv4-ranges**: 許可する IPv4 範囲のカンマ区切りリスト。(デフォルト: 全ての IPv4 アドレスを許可) - **--ipv6-ranges**: 許可する IPv6 範囲のカンマ区切りリスト。(デフォルト: 全ての IPv6 アドレスを許可) - **--disable-ipv6**: IPv6 での接続を無効にします (デフォルト: 有効) @@ -145,6 +146,7 @@ cdk bootstrap aws:///ap-northeast-1 - `bedrockRegion`: Bedrock が利用できるリージョン - `allowedIpV4AddressRanges`, `allowedIpV6AddressRanges`: 許可する IP アドレス範囲の指定 + - `enableLambdaSnapStart`: デフォルトでは true ですが、[Python 関数の Lambda SnapStart をサポートしていないリージョン](https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html#snapstart-supported-regions)にデプロイする場合は false に変更してください。 - プロジェクトをデプロイします @@ -257,6 +259,14 @@ cli および CDK を利用されている場合、`cdk destroy`を実行して "enableBedrockCrossRegionInference": true ``` +### Lambda SnapStart + +[Lambda SnapStart](https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html) は Lambda 関数のコールドスタート時間を短縮し、レスポンスタイムの改善によってユーザー体験を向上させます。ただし、Python 関数については[キャッシュサイズに比例した利用料金](https://aws.amazon.com/lambda/pricing/#SnapStart_Pricing)が発生するのに加え、[一部のリージョン](https://docs.aws.amazon.com/lambda/latest/dg/snapstart.html#snapstart-supported-regions)では現在利用できません。SnapStart を無効化するには、`cdk.json` を以下のように編集します。 + +```json +"enableLambdaSnapStart": false +``` + ### ローカルでの開発について - [こちら](./LOCAL_DEVELOPMENT_ja.md)を参照ください。