From 53a8477af1bde099477942bf4005189e922f2874 Mon Sep 17 00:00:00 2001 From: Dmitry Gulin Date: Wed, 10 Dec 2025 18:31:28 -0500 Subject: [PATCH 1/2] add lambda-durable-managed-instances-cdk pattern --- .../.gitignore | 9 + .../.npmignore | 6 + .../README.md | 240 ++++++++++++++++++ .../bin/app.ts | 13 + lambda-durable-managed-instances-cdk/cdk.json | 101 ++++++++ .../events/basic-order.json | 3 + .../example-pattern.json | 66 +++++ .../lambda/step-wait-step.mts | 26 ++ .../lib/demo-stack.ts | 44 ++++ .../package.json | 24 ++ .../test-lambda.sh | 125 +++++++++ .../tsconfig.json | 32 +++ 12 files changed, 689 insertions(+) create mode 100644 lambda-durable-managed-instances-cdk/.gitignore create mode 100644 lambda-durable-managed-instances-cdk/.npmignore create mode 100644 lambda-durable-managed-instances-cdk/README.md create mode 100644 lambda-durable-managed-instances-cdk/bin/app.ts create mode 100644 lambda-durable-managed-instances-cdk/cdk.json create mode 100644 lambda-durable-managed-instances-cdk/events/basic-order.json create mode 100644 lambda-durable-managed-instances-cdk/example-pattern.json create mode 100644 lambda-durable-managed-instances-cdk/lambda/step-wait-step.mts create mode 100644 lambda-durable-managed-instances-cdk/lib/demo-stack.ts create mode 100644 lambda-durable-managed-instances-cdk/package.json create mode 100755 lambda-durable-managed-instances-cdk/test-lambda.sh create mode 100644 lambda-durable-managed-instances-cdk/tsconfig.json diff --git a/lambda-durable-managed-instances-cdk/.gitignore b/lambda-durable-managed-instances-cdk/.gitignore new file mode 100644 index 0000000000..a194581fd3 --- /dev/null +++ b/lambda-durable-managed-instances-cdk/.gitignore @@ -0,0 +1,9 @@ +*.js +!jest.config.js +*.d.ts +node_modules + +# CDK asset staging directory +.cdk.staging +cdk.out +cdk.context.json \ No newline at end of file diff --git a/lambda-durable-managed-instances-cdk/.npmignore b/lambda-durable-managed-instances-cdk/.npmignore new file mode 100644 index 0000000000..c1d6d45dcf --- /dev/null +++ b/lambda-durable-managed-instances-cdk/.npmignore @@ -0,0 +1,6 @@ +*.ts +!*.d.ts + +# CDK asset staging directory +.cdk.staging +cdk.out diff --git a/lambda-durable-managed-instances-cdk/README.md b/lambda-durable-managed-instances-cdk/README.md new file mode 100644 index 0000000000..56ed9fb0ca --- /dev/null +++ b/lambda-durable-managed-instances-cdk/README.md @@ -0,0 +1,240 @@ +# Lambda durable functions on Lambda Managed Instances + +This pattern demonstrates how to implement Lambda durable functions running on Lambda Managed Instances using AWS CDK. Lambda durable functions allow Lambda functions to maintain state and execution context across multiple invocations, while Lambda Managed Instances provide predictable performance and reduced cold starts. + +Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/lambda-durable-managed-instances-cdk + +Important: this application uses various AWS services and there are costs associated with these services after the Free Tier usage - please see the [AWS Pricing page](https://aws.amazon.com/pricing/) for details. You are responsible for any AWS costs incurred. No warranty is implied in this example. + +**Note**: Lambda Managed Instances provision EC2 instances that are **NOT eligible for the AWS Free Tier**. These instances will incur charges immediately upon deployment, regardless of your Free Tier status. + +## Requirements + +* [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources. +* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured +* [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) +* [AWS CDK](https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html) installed and configured +* [Node.js](https://nodejs.org/) (version 24.x or later) + +## Deployment Instructions + +1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository: + ``` + git clone https://github.com/aws-samples/serverless-patterns + ``` +1. Change directory to the pattern directory: + ``` + cd lambda-durable-managed-instances-cdk + ``` +1. Install the project dependencies: + ``` + npm install + ``` +1. Build the project: + ``` + npm run build + ``` +1. Deploy the CDK stack: + ``` + npx cdk deploy + ``` + Note: This stack is currently configured to deploy to the `us-east-2` region. Please refer to the [AWS capabilities explorer](https://builder.aws.com/build/capabilities/explore) for feature availability in your desired region. + +1. Note the outputs from the CDK deployment process. These contain the resource names and/or ARNs which are used for testing. + +## How it works + +This pattern demonstrates the integration of two key Lambda features: + +### Lambda durable functions +[Lambda durable functions](https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html) enable Lambda functions to maintain state and execution context across multiple invocations. This allows for: +- Long-running workflows that can span multiple function invocations +- State persistence between executions +- Improved reliability for complex processing tasks +- Better handling of timeouts and retries + +### Lambda Managed Instances +[Lambda Managed Instances](https://docs.aws.amazon.com/lambda/latest/dg/lambda-managed-instances.html) provide: +- Predictable performance with pre-warmed execution environments +- Reduced cold start latency +- Consistent execution characteristics +- Better resource utilization for frequently invoked functions + +The combination of these features allows for building robust, stateful serverless applications that can handle complex workflows while maintaining high performance and reliability. + +## Testing + +After deployment, you can test the Lambda durable function using the provided test script, AWS CLI, or AWS Console. + +### Automated Testing Script + +The pattern includes a comprehensive test script that demonstrates all aspects of durable function execution: + +1. **Make the test script executable and run it**: + ```bash + chmod +x test-lambda.sh + ./test-lambda.sh [profile] [region] + ``` + + Examples: + ```bash + # Using default AWS profile and region + ./test-lambda.sh + + # Using specific profile and region + ./test-lambda.sh my-profile us-west-2 + ``` + +2. **What the script does**: + - Invokes the function asynchronously with a test payload + - Extracts the durable execution ARN from the response + - Shows real-time execution history with step details + - Displays CloudWatch logs with execution flow + - Retrieves the final execution result with input/output JSON + - Provides helpful CLI commands for manual inspection + +3. **Script output includes**: + - Function invocation status and durable execution ARN + - Step-by-step execution history showing the step-wait-step pattern + - Detailed logs with business logic tracing + - Final execution result with timestamps and processed data + +### Manual AWS CLI Testing + +#### Basic Function Invocation + +1. **Synchronous invocation** (for immediate response): + ```bash + aws lambda invoke \ + --function-name step-wait-step-durable-function \ + --payload file://events/basic-order.json \ + --cli-binary-format raw-in-base64-out \ + --region us-east-2 \ + response.json + ``` + +2. **Asynchronous invocation** (recommended for durable functions): + ```bash + aws lambda invoke \ + --function-name step-wait-step-durable-function:$LATEST.PUBLISHED \ + --invocation-type Event \ + --payload file://events/basic-order.json \ + --cli-binary-format raw-in-base64-out \ + --region us-east-2 \ + response.json + ``` + +#### Monitoring Durable Execution + +After invoking the function asynchronously, you'll receive a durable execution ARN. Use these commands to monitor the execution: + +1. **Get execution details and result**: + ```bash + aws lambda get-durable-execution \ + --durable-execution-arn "YOUR_EXECUTION_ARN" \ + --region us-east-2 + ``` + +2. **View execution history** (step-by-step flow): + ```bash + aws lambda get-durable-execution-history \ + --durable-execution-arn "YOUR_EXECUTION_ARN" \ + --region us-east-2 + ``` + +3. **List all executions for the function**: + ```bash + aws lambda list-durable-executions-by-function \ + --function-name step-wait-step-durable-function \ + --region us-east-2 + ``` + +4. **View CloudWatch logs**: + ```bash + aws logs filter-log-events \ + --log-group-name /aws/lambda/step-wait-step-durable-function \ + --start-time $(date -d '5 minutes ago' +%s)000 \ + --region us-east-2 \ + --filter-pattern 'INFO' + ``` + +### AWS Console Testing + +1. Navigate to the Lambda service in the AWS Console +2. Find the function named `step-wait-step-durable-function` +3. Create a test event using the payload from `events/basic-order.json` or create a custom payload with: + ```json + { + "orderId": "your-test-order-id" + } + ``` +4. Execute the test and observe the results in the execution logs + +### Expected Behavior + +The function demonstrates the **step-wait-step pattern** with durable execution: + +1. **Step 1 - Validate Order**: + - Processes the input order ID + - Returns validation status with timestamp + - Logs: "Validating order [orderId]" + +2. **Wait Phase - 5 Second Delay**: + - Durable wait without consuming execution time + - Function execution pauses and resumes automatically + - Logs: "Order validated, waiting 5 seconds before processing" + +3. **Step 2 - Process Order**: + - Final processing with completion timestamp + - Returns processed order with both validation and processing timestamps + - Logs: "Processing order [orderId]" and "Step-wait-step execution completed" + +### Sample Output + +**Execution History** shows the durable execution flow: +``` +ExecutionStarted → StepStarted (validate-order) → StepSucceeded → +WaitStarted (wait 5s) → WaitSucceeded → StepStarted (process-order) → +StepSucceeded → ExecutionSucceeded +``` + +**Final Result** contains the processed order data: +```json +{ + "orderId": "order-123", + "status": "processed", + "validatedAt": 1765404928643, + "processedAt": 1765404934023 +} +``` + +### Monitoring and Observability + +Monitor the execution through multiple channels: +- **CloudWatch Logs**: Detailed execution flow and business logic tracing +- **Durable Execution History**: Step-by-step execution events with timestamps +- **Lambda Metrics**: Function performance and invocation statistics +- **Execution State**: Real-time status and result data via AWS CLI + +## Regional Availability + +This stack is configured to deploy to the `us-east-2` region. Before deploying to a different region, please verify that both Lambda durable functions and Lambda Managed Instances features are available in your target region by using the [AWS capabilities explorer](https://builder.aws.com/build/capabilities/explore) or consulting the official AWS documentation: + +- [Lambda durable functions documentation](https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html) +- [Lambda Managed Instances documentation](https://docs.aws.amazon.com/lambda/latest/dg/lambda-managed-instances.html) + +## Cleanup + +1. Delete the stack + ```bash + npx cdk destroy + ``` +1. Confirm the stack has been deleted by checking the AWS CloudFormation console or running: + ```bash + aws cloudformation describe-stacks --stack-name lambda-durable-functions-managed-instances --region us-east-2 + ``` + +---- +Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +SPDX-License-Identifier: MIT-0 \ No newline at end of file diff --git a/lambda-durable-managed-instances-cdk/bin/app.ts b/lambda-durable-managed-instances-cdk/bin/app.ts new file mode 100644 index 0000000000..45b0a2fc54 --- /dev/null +++ b/lambda-durable-managed-instances-cdk/bin/app.ts @@ -0,0 +1,13 @@ +#!/usr/bin/env node +import { App } from 'aws-cdk-lib/core'; +import { DemoStack } from '../lib/demo-stack'; + +const app = new App(); +new DemoStack(app, 'LambdaDurableFunctionsManagedInstancesDemo', { + stackName: 'lambda-durable-functions-managed-instances', + env: { + account: process.env.CDK_DEFAULT_ACCOUNT, + region: 'us-east-2' + }, + description: 'POC stack demonstrating Lambda durable functions running on Lambda Managed Instances', +}); diff --git a/lambda-durable-managed-instances-cdk/cdk.json b/lambda-durable-managed-instances-cdk/cdk.json new file mode 100644 index 0000000000..93f6f49b73 --- /dev/null +++ b/lambda-durable-managed-instances-cdk/cdk.json @@ -0,0 +1,101 @@ +{ + "app": "npx ts-node --prefer-ts-exts bin/app.ts", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "test" + ] + }, + "context": { + "@aws-cdk/aws-signer:signingProfileNamePassedToCfn": true, + "@aws-cdk/aws-ecs-patterns:secGroupsDisablesImplicitOpenListener": true, + "@aws-cdk/aws-lambda:recognizeLayerVersion": true, + "@aws-cdk/core:checkSecretUsage": true, + "@aws-cdk/core:target-partitions": [ + "aws", + "aws-cn" + ], + "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, + "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, + "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, + "@aws-cdk/aws-iam:minimizePolicies": true, + "@aws-cdk/core:validateSnapshotRemovalPolicy": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, + "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, + "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, + "@aws-cdk/core:enablePartitionLiterals": true, + "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, + "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, + "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, + "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, + "@aws-cdk/aws-route53-patters:useCertificate": true, + "@aws-cdk/customresources:installLatestAwsSdkDefault": false, + "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, + "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, + "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, + "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, + "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, + "@aws-cdk/aws-redshift:columnId": true, + "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, + "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, + "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, + "@aws-cdk/aws-kms:aliasNameRef": true, + "@aws-cdk/aws-kms:applyImportedAliasPermissionsToPrincipal": true, + "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true, + "@aws-cdk/core:includePrefixInUniqueNameGeneration": true, + "@aws-cdk/aws-efs:denyAnonymousAccess": true, + "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true, + "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true, + "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true, + "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true, + "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true, + "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true, + "@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true, + "@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true, + "@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true, + "@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true, + "@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true, + "@aws-cdk/aws-eks:nodegroupNameAttribute": true, + "@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true, + "@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true, + "@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false, + "@aws-cdk/aws-s3:keepNotificationInImportedBucket": false, + "@aws-cdk/core:explicitStackTags": true, + "@aws-cdk/aws-ecs:enableImdsBlockingDeprecatedFeature": false, + "@aws-cdk/aws-ecs:disableEcsImdsBlocking": true, + "@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": true, + "@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": true, + "@aws-cdk/aws-ec2:ec2SumTImeoutEnabled": true, + "@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": true, + "@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": true, + "@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": true, + "@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": true, + "@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": true, + "@aws-cdk/aws-ec2:bastionHostUseAmazonLinux2023ByDefault": true, + "@aws-cdk/aws-route53-targets:userPoolDomainNameMethodWithoutCustomResource": true, + "@aws-cdk/aws-elasticloadbalancingV2:albDualstackWithoutPublicIpv4SecurityGroupRulesDefault": true, + "@aws-cdk/aws-iam:oidcRejectUnauthorizedConnections": true, + "@aws-cdk/core:enableAdditionalMetadataCollection": true, + "@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy": false, + "@aws-cdk/aws-s3:setUniqueReplicationRoleName": true, + "@aws-cdk/aws-events:requireEventBusPolicySid": true, + "@aws-cdk/core:aspectPrioritiesMutating": true, + "@aws-cdk/aws-dynamodb:retainTableReplica": true, + "@aws-cdk/aws-stepfunctions:useDistributedMapResultWriterV2": true, + "@aws-cdk/s3-notifications:addS3TrustKeyPolicyForSnsSubscriptions": true, + "@aws-cdk/aws-ec2:requirePrivateSubnetsForEgressOnlyInternetGateway": true, + "@aws-cdk/aws-s3:publicAccessBlockedByDefault": true, + "@aws-cdk/aws-lambda:useCdkManagedLogGroup": true + } +} diff --git a/lambda-durable-managed-instances-cdk/events/basic-order.json b/lambda-durable-managed-instances-cdk/events/basic-order.json new file mode 100644 index 0000000000..2acce421e0 --- /dev/null +++ b/lambda-durable-managed-instances-cdk/events/basic-order.json @@ -0,0 +1,3 @@ +{ + "orderId": "order-123" +} \ No newline at end of file diff --git a/lambda-durable-managed-instances-cdk/example-pattern.json b/lambda-durable-managed-instances-cdk/example-pattern.json new file mode 100644 index 0000000000..558e42fb11 --- /dev/null +++ b/lambda-durable-managed-instances-cdk/example-pattern.json @@ -0,0 +1,66 @@ +{ + "title": "Lambda durable functions on Lambda Managed Instances", + "description": "This pattern demonstrates how to implement Lambda durable functions running on Lambda Managed Instances using AWS CDK.", + "language": "TypeScript", + "level": "200", + "framework": "AWS CDK", + "introBox": { + "headline": "How it works", + "text": [ + "This sample project demonstrates how to implement Lambda durable functions running on Lambda Managed Instances. Lambda durable functions allow Lambda functions to maintain state and execution context across multiple invocations, enabling long-running workflows that can span multiple function executions.", + "Lambda Managed Instances provide predictable performance with pre-warmed execution environments, reduced cold start latency, and consistent execution characteristics. The combination of these features allows for building robust, stateful serverless applications that can handle complex workflows while maintaining high performance.", + "The pattern implements a step-wait-step workflow where the function validates an order, waits for 5 seconds using durable execution, and then processes the order. The execution state is maintained across invocations, demonstrating how durable functions can pause and resume execution seamlessly.", + "This pattern deploys one Lambda Function with durable configuration, a VPC with subnets and security groups, and a Lambda Capacity Provider for managed instances." + ] + }, + "gitHub": { + "template": { + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/lambda-durable-managed-instances-cdk", + "templateURL": "serverless-patterns/lambda-durable-managed-instances-cdk", + "projectFolder": "lambda-durable-managed-instances-cdk", + "templateFile": "lib/demo-stack.ts" + } + }, + "resources": { + "bullets": [ + { + "text": "Lambda durable functions", + "link": "https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html" + }, + { + "text": "Lambda Managed Instances", + "link": "https://docs.aws.amazon.com/lambda/latest/dg/lambda-managed-instances.html" + }, + { + "text": "AWS Lambda durable execution SDK for JavaScript", + "link": "https://www.npmjs.com/package/@aws/durable-execution-sdk-js" + }, + { + "text": "AWS capabilities explorer", + "link": "https://builder.aws.com/build/capabilities/explore" + } + ] + }, + "deploy": { + "text": [ + "cdk deploy" + ] + }, + "testing": { + "text": [ + "See the GitHub repo for detailed testing instructions." + ] + }, + "cleanup": { + "text": [ + "Delete the stack: cdk destroy." + ] + }, + "authors": [ + { + "name": "Dmitry Gulin", + "bio": "Senior Modernization Architect, AWS.", + "linkedin": "dmitry-gulin" + } + ] +} \ No newline at end of file diff --git a/lambda-durable-managed-instances-cdk/lambda/step-wait-step.mts b/lambda-durable-managed-instances-cdk/lambda/step-wait-step.mts new file mode 100644 index 0000000000..aa1c6037c9 --- /dev/null +++ b/lambda-durable-managed-instances-cdk/lambda/step-wait-step.mts @@ -0,0 +1,26 @@ +import { withDurableExecution, DurableContext } from '@aws/durable-execution-sdk-js'; + +export const handler = withDurableExecution(async (event: { orderId: string }, context: DurableContext) => { + context.logger.info("Starting step-wait-step execution for order", event.orderId); + + const validated = await context.step("validate-order", async () => { + context.logger.info("Validating order", event.orderId); + return { orderId: event.orderId, status: "validated", validatedAt: Date.now() }; + }); + + context.logger.info("Order validated, waiting 5 seconds before processing"); + await context.wait("wait 5s", { seconds: 5 }); + + const processed = await context.step("process-order", async () => { + context.logger.info("Processing order", event.orderId); + return { + orderId: validated.orderId, + status: "processed", + validatedAt: validated.validatedAt, + processedAt: Date.now() + }; + }); + + context.logger.info("Step-wait-step execution completed for order", event.orderId); + return processed; +}); \ No newline at end of file diff --git a/lambda-durable-managed-instances-cdk/lib/demo-stack.ts b/lambda-durable-managed-instances-cdk/lib/demo-stack.ts new file mode 100644 index 0000000000..998bebe178 --- /dev/null +++ b/lambda-durable-managed-instances-cdk/lib/demo-stack.ts @@ -0,0 +1,44 @@ +import { Stack, StackProps, Duration, CfnOutput } from 'aws-cdk-lib/core'; +import { NodejsFunction, OutputFormat } from 'aws-cdk-lib/aws-lambda-nodejs'; +import { Architecture, CapacityProvider, Runtime } from 'aws-cdk-lib/aws-lambda'; +import { Construct } from 'constructs'; +import { SecurityGroup, Vpc } from 'aws-cdk-lib/aws-ec2'; + +export class DemoStack extends Stack { + constructor(scope: Construct, id: string, props?: StackProps) { + super(scope, id, props); + + const durableFunction = new NodejsFunction(this, 'StepWaitStepFunction', { + entry: 'lambda/step-wait-step.mts', + handler: 'handler', + runtime: Runtime.NODEJS_24_X, + architecture: Architecture.ARM_64, + functionName: 'step-wait-step-durable-function', + description: 'Lambda durable function demonstrating step-wait-step pattern', + bundling: { + format: OutputFormat.ESM, + mainFields: ['module', 'main'], + }, + durableConfig: { + executionTimeout: Duration.hours(1), retentionPeriod: Duration.days(30), + }, + }); + + const vpc = new Vpc(this, 'LambdaManagedInstancesVPC'); + const securityGroup = new SecurityGroup(this, 'SecurityGroup', { vpc }); + + const capacityProvider = new CapacityProvider(this, 'LambdaCapacityProvider', { + capacityProviderName: 'lambda-capacity-provider', + subnets: vpc.privateSubnets, + securityGroups: [securityGroup], + architectures: [Architecture.ARM_64], + }); + + capacityProvider.addFunction(durableFunction); + + new CfnOutput(this, 'FunctionName', { + value: durableFunction.functionName, + description: 'Lambda function name for CLI invocation', + }); + } +} diff --git a/lambda-durable-managed-instances-cdk/package.json b/lambda-durable-managed-instances-cdk/package.json new file mode 100644 index 0000000000..8c7c4db170 --- /dev/null +++ b/lambda-durable-managed-instances-cdk/package.json @@ -0,0 +1,24 @@ +{ + "name": "lambda-durable-managed-instances-cdk", + "version": "0.1.0", + "bin": { + "lambda-durable-managed-instances-cdk": "bin/app.js" + }, + "scripts": { + "build": "tsc", + "watch": "tsc -w", + "cdk": "cdk" + }, + "devDependencies": { + "@types/node": "^24.10.2", + "aws-cdk": "2.1033.0", + "esbuild": "^0.27.1", + "ts-node": "^10.9.2", + "typescript": "~5.9.3" + }, + "dependencies": { + "@aws/durable-execution-sdk-js": "^1.0.0", + "aws-cdk-lib": "2.232.1", + "constructs": "^10.4.3" + } +} diff --git a/lambda-durable-managed-instances-cdk/test-lambda.sh b/lambda-durable-managed-instances-cdk/test-lambda.sh new file mode 100755 index 0000000000..daf271badb --- /dev/null +++ b/lambda-durable-managed-instances-cdk/test-lambda.sh @@ -0,0 +1,125 @@ +#!/bin/bash + +# Test script for Lambda durable function +# Usage: ./test-lambda.sh [profile] [region] + +set -e + +# Configuration +FUNCTION_NAME="step-wait-step-durable-function" +FUNCTION_VERSION="\$LATEST.PUBLISHED" +PAYLOAD_FILE="events/basic-order.json" +RESPONSE_FILE="response.json" +LOG_GROUP="/aws/lambda/step-wait-step-durable-function" + +# Default values +PROFILE="${1:-default}" +REGION="${2:-us-east-2}" + +echo "🚀 Testing Lambda durable function..." +echo "Function: $FUNCTION_NAME" +echo "Profile: $PROFILE" +echo "Region: $REGION" +echo + +# Check if payload file exists +if [ ! -f "$PAYLOAD_FILE" ]; then + echo "❌ Error: Payload file $PAYLOAD_FILE not found" + exit 1 +fi + +echo "📄 Using payload:" +cat "$PAYLOAD_FILE" +echo + +# Invoke Lambda function +echo "⚡ Invoking Lambda function..." +INVOKE_OUTPUT=$(aws lambda invoke \ + --function-name "$FUNCTION_NAME:$FUNCTION_VERSION" \ + --invocation-type Event \ + --payload "file://$PAYLOAD_FILE" \ + --cli-binary-format raw-in-base64-out \ + --region "$REGION" \ + --profile "$PROFILE" \ + "$RESPONSE_FILE" 2>&1) + +echo "$INVOKE_OUTPUT" + +echo + +# Extract durable execution ARN from the invoke output +echo "🔍 Extracting durable execution ARN from output..." +EXECUTION_ARN=$(echo "$INVOKE_OUTPUT" | grep -o 'arn:aws:lambda:[^"]*durable-execution/[^"]*' | head -1) + +if [ -n "$EXECUTION_ARN" ]; then + echo "🔗 Durable Execution ARN:" + echo "$EXECUTION_ARN" + echo +else + echo "⚠️ No durable execution ARN found in invoke output" + echo "📋 Full invoke output:" + echo "$INVOKE_OUTPUT" + echo +fi + +# Wait for execution to start +echo "⏳ Waiting 10 seconds for execution to start..." +sleep 10 + +# Show durable execution history +if [ -n "$EXECUTION_ARN" ]; then + echo "📜 Durable execution history (initial):" + aws lambda get-durable-execution-history \ + --durable-execution-arn "$EXECUTION_ARN" \ + --region "$REGION" \ + --profile "$PROFILE" \ + --query 'Events[].{EventType:EventType,Name:Name,Timestamp:EventTimestamp}' \ + --output table || echo "⚠️ Failed to get execution history: $?" + echo +fi + +# Show recent logs +echo "📊 Recent logs (last 2 minutes):" +START_TIME=$(($(date +%s) - 120))000 +aws logs filter-log-events \ + --log-group-name "$LOG_GROUP" \ + --start-time "$START_TIME" \ + --region "$REGION" \ + --profile "$PROFILE" \ + --filter-pattern 'INFO' \ + --query 'events[].[timestamp,message]' \ + --output table + +# Wait for execution to complete and show final history +if [ -n "$EXECUTION_ARN" ]; then + echo "⏳ Waiting additional 10 seconds for execution to complete..." + sleep 10 + + echo "📜 Final durable execution history:" + aws lambda get-durable-execution-history \ + --durable-execution-arn "$EXECUTION_ARN" \ + --region "$REGION" \ + --profile "$PROFILE" \ + --query 'Events[].{EventType:EventType,SubType:SubType,Name:Name,Timestamp:EventTimestamp}' \ + --output table || echo "⚠️ Failed to get final execution history: $?" + echo + + echo "🎯 Durable execution result:" + aws lambda get-durable-execution \ + --durable-execution-arn "$EXECUTION_ARN" \ + --region "$REGION" \ + --profile "$PROFILE" \ + --query '{Status:Status,InputPayload:InputPayload,Result:Result,StartTime:StartTimestamp,EndTime:EndTimestamp}' \ + --output table || echo "⚠️ Failed to get execution result: $?" + echo +fi + +echo "✅ Test completed!" +echo "💡 To view all logs: aws logs filter-log-events --log-group-name $LOG_GROUP --start-time $START_TIME --region $REGION --profile $PROFILE" +if [ -n "$EXECUTION_ARN" ]; then + echo "💡 To view execution history: aws lambda get-durable-execution-history --durable-execution-arn $EXECUTION_ARN --region $REGION --profile $PROFILE" + echo "💡 To view execution result: aws lambda get-durable-execution --durable-execution-arn $EXECUTION_ARN --region $REGION --profile $PROFILE" +fi + +# Cleanup +rm -f "$RESPONSE_FILE" \ No newline at end of file diff --git a/lambda-durable-managed-instances-cdk/tsconfig.json b/lambda-durable-managed-instances-cdk/tsconfig.json new file mode 100644 index 0000000000..bfc61bf833 --- /dev/null +++ b/lambda-durable-managed-instances-cdk/tsconfig.json @@ -0,0 +1,32 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "NodeNext", + "moduleResolution": "NodeNext", + "lib": [ + "es2022" + ], + "declaration": true, + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "noImplicitThis": true, + "alwaysStrict": true, + "noUnusedLocals": false, + "noUnusedParameters": false, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": false, + "inlineSourceMap": true, + "inlineSources": true, + "experimentalDecorators": true, + "strictPropertyInitialization": false, + "skipLibCheck": true, + "typeRoots": [ + "./node_modules/@types" + ] + }, + "exclude": [ + "node_modules", + "cdk.out" + ] +} From b2d4308403157e8c3f1f0c8dadabce432f786a3b Mon Sep 17 00:00:00 2001 From: Dmitry Gulin Date: Thu, 11 Dec 2025 11:37:29 -0500 Subject: [PATCH 2/2] add CDK minimum version requirement --- lambda-durable-managed-instances-cdk/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lambda-durable-managed-instances-cdk/README.md b/lambda-durable-managed-instances-cdk/README.md index 56ed9fb0ca..af4526fff4 100644 --- a/lambda-durable-managed-instances-cdk/README.md +++ b/lambda-durable-managed-instances-cdk/README.md @@ -11,9 +11,9 @@ Important: this application uses various AWS services and there are costs associ ## Requirements * [Create an AWS account](https://portal.aws.amazon.com/gp/aws/developer/registration/index.html) if you do not already have one and log in. The IAM user that you use must have sufficient permissions to make necessary AWS service calls and manage AWS resources. -* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured +* [AWS CLI v2](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) (latest available version) installed and configured * [Git Installed](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) -* [AWS CDK](https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html) installed and configured +* [AWS CDK](https://docs.aws.amazon.com/cdk/latest/guide/getting_started.html) (version 2.232.0 or later) installed and configured * [Node.js](https://nodejs.org/) (version 24.x or later) ## Deployment Instructions