From cb41d6f8904414e393ec4969f0e8b6372d6675b5 Mon Sep 17 00:00:00 2001 From: dsiz Date: Wed, 18 Feb 2026 19:43:12 +0530 Subject: [PATCH 1/8] adding lambda-durable-functions-nodejs-calling-ecs --- .../.gitignore | 26 ++ .../README.md | 220 +++++++++++++ .../example-pattern.json | 68 ++++ .../src/callback-handler.js | 95 ++++++ .../src/package.json | 23 ++ .../src/polling-handler.js | 79 +++++ .../template.yaml | 311 ++++++++++++++++++ 7 files changed, 822 insertions(+) create mode 100644 lambda-durable-functions-nodejs-calling-ecs/.gitignore create mode 100644 lambda-durable-functions-nodejs-calling-ecs/README.md create mode 100644 lambda-durable-functions-nodejs-calling-ecs/example-pattern.json create mode 100644 lambda-durable-functions-nodejs-calling-ecs/src/callback-handler.js create mode 100644 lambda-durable-functions-nodejs-calling-ecs/src/package.json create mode 100644 lambda-durable-functions-nodejs-calling-ecs/src/polling-handler.js create mode 100644 lambda-durable-functions-nodejs-calling-ecs/template.yaml diff --git a/lambda-durable-functions-nodejs-calling-ecs/.gitignore b/lambda-durable-functions-nodejs-calling-ecs/.gitignore new file mode 100644 index 000000000..dc6e3ed0b --- /dev/null +++ b/lambda-durable-functions-nodejs-calling-ecs/.gitignore @@ -0,0 +1,26 @@ +# Node modules +node_modules/ +package-lock.json + +# SAM build artifacts +.aws-sam/ +samconfig.toml + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Test outputs +response.json +*.log + +# Environment +.env +.env.local diff --git a/lambda-durable-functions-nodejs-calling-ecs/README.md b/lambda-durable-functions-nodejs-calling-ecs/README.md new file mode 100644 index 000000000..25b4c04bf --- /dev/null +++ b/lambda-durable-functions-nodejs-calling-ecs/README.md @@ -0,0 +1,220 @@ +# AWS Lambda durable functions with Amazon ECS Integration + +This pattern demonstrates how to use AWS Lambda durable functions to orchestrate long-running Amazon ECS Fargate tasks. The Lambda function can wait up to 24 hours for ECS task completion without incurring compute charges during the wait period. + +**Important:** Please check the [AWS documentation](https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html) for regions currently supported by AWS Lambda durable functions. + +Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/lambda-durable-functions-nodejs-calling-ecs + +## Architecture + +![Architecture Diagram](architecture.png) + +The pattern uses Lambda durable functions with the callback pattern to orchestrate ECS Fargate tasks cost-effectively. + +### Workflow Steps + +1. **Lambda function invoked** with task parameters (message, processing time) +2. **Durable function creates callback ID** using `context.waitForCallback()` +3. **ECS Fargate task started** with callback ID passed as environment variable +4. **Lambda function pauses** (no compute charges during wait) +5. **ECS task processes workload** and logs progress to CloudWatch +6. **ECS task completes** (in production, would call `SendDurableExecutionCallbackSuccess`) +7. **Lambda function resumes** and returns result + +## Key Features + +- ✅ **24-Hour Wait Time** - Can wait up to 24 hours for ECS task completion +- ✅ **No Compute Charges During Wait** - Function suspended during wait period +- ✅ **Callback Pattern** - ECS tasks call Lambda APIs directly to resume execution +- ✅ **CloudWatch Logs** - Full visibility into both Lambda and ECS execution +- ✅ **Generic Container** - Uses public Python image, easily replaceable +- ✅ **Fargate Serverless** - No EC2 instances to manage + +## Prerequisites + +* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured +* [AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) installed +* Node.js 22.x runtime (automatically provided by Lambda) + +## Deployment + +1. Navigate to the pattern directory: + ```bash + cd lambda-durable-functions-nodejs-calling-ecs + ``` + +2. Build the SAM application: + ```bash + sam build + ``` + +3. Deploy the application: + ```bash + sam deploy --guided + ``` + + During the guided deployment: + - Accept default values or customize as needed + - Allow SAM CLI to create IAM roles when prompted + - Note the function name from the outputs + +4. Note the `CallbackFunctionName` from the CloudFormation outputs + +## Testing + +### Test the Callback Pattern + +Invoke the Lambda function with a test payload: + +```bash +aws lambda invoke \ + --function-name :prod \ + --invocation-type Event \ + --payload '{"message":"Test ECS task","processingTime":8}' \ + --cli-binary-format raw-in-base64-out \ + response.json +``` + +**Note:** The `:prod` alias is required for durable functions. + +### Monitor Execution + +Check Lambda logs: +```bash +aws logs tail /aws/lambda/ --since 2m --follow +``` + +Check ECS task logs: +```bash +aws logs tail /ecs/lambda-ecs-durable-demo --since 2m --follow +``` + +### Expected Output + +**Lambda Logs:** +``` +Starting Lambda durable function - Callback Pattern +Callback ID created: +Starting ECS task with callback ID... +ECS task started: arn:aws:ecs:... +``` + +**ECS Logs:** +``` +=== ECS Task Started === +Callback ID: +Message: Test ECS task +Processing Time: 8 seconds +Simulating work... +=== Task Completed Successfully === +Result: {"status":"completed","message":"Processed: Test ECS task"} +Note: In production, call Lambda SendDurableExecutionCallbackSuccess API here +``` + +## How It Works + +### Lambda durable function (Node.js) + +The Lambda function uses the `@aws/durable-execution-sdk-js` package: + +```javascript +const { withDurableExecution } = require('@aws/durable-execution-sdk-js'); + +exports.handler = withDurableExecution(async (event, context) => { + // Create callback and start ECS task + const result = await context.waitForCallback( + 'ecs-task-callback', + async (callbackId) => { + // Start ECS task with callback ID + const response = await ecs.send(new RunTaskCommand({ + // ... pass callbackId as environment variable + })); + }, + { timeout: { hours: 1 } } + ); + + return result; +}); +``` + +### ECS Task (Python) + +The ECS container receives the callback ID and processes the workload. In production, it would call the Lambda API: + +```bash +aws lambda send-durable-execution-callback-success \ + --callback-id $CALLBACK_ID \ + --result '{"status":"completed","data":"..."}' +``` + +### Key Configuration + +**Lambda Function:** +- Runtime: `nodejs22.x` (required for durable functions) +- `AutoPublishAlias: prod` (required) +- `DurableConfig` with execution timeout and retention period + +**ECS Task:** +- Launch type: `FARGATE` +- Public subnet with `assignPublicIp: ENABLED` +- Container image: `public.ecr.aws/docker/library/python:3.12-alpine` +- CloudWatch Logs enabled + +## Customization + +### Replace the ECS Container + +The pattern uses a generic Python container for demonstration. To use your own container: + +1. Update the `Image` in the `ECSTaskDefinition` resource +2. Ensure your container: + - Reads the `CALLBACK_ID` environment variable + - Calls `aws lambda send-durable-execution-callback-success` on completion + - Calls `aws lambda send-durable-execution-callback-failure` on error + +### Adjust Timeouts + +Modify the durable function timeout in `template.yaml`: + +```yaml +DurableConfig: + ExecutionTimeout: 86400 # 24 hours in seconds + RetentionPeriodInDays: 7 +``` + +And the callback timeout in the handler: + +```javascript +context.waitForCallback('ecs-task-callback', async (callbackId) => { + // ... +}, { + timeout: { hours: 24 }, // Maximum wait time + heartbeatTimeout: { minutes: 5 } // Optional heartbeat +}) +``` + +## Cleanup + +Delete the stack: + +```bash +sam delete +``` + +## Cost Considerations + +- **Lambda:** Charged only for active execution time, not during wait periods +- **ECS Fargate:** Charged per vCPU and memory per second while tasks run +- **CloudWatch Logs:** Charged for log ingestion and storage +- **VPC:** NAT Gateway charges if using private subnets (this pattern uses public subnets) + +## Additional Resources + +- [AWS Lambda durable functions Documentation](https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html) +- [Amazon ECS on AWS Fargate](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/AWS_Fargate.html) +- [AWS SAM Documentation](https://docs.aws.amazon.com/serverless-application-model/) + +--- + +© 2026 Amazon Web Services, Inc. or its affiliates. All Rights Reserved. diff --git a/lambda-durable-functions-nodejs-calling-ecs/example-pattern.json b/lambda-durable-functions-nodejs-calling-ecs/example-pattern.json new file mode 100644 index 000000000..a1bc77d31 --- /dev/null +++ b/lambda-durable-functions-nodejs-calling-ecs/example-pattern.json @@ -0,0 +1,68 @@ +{ + "title": "AWS Lambda durable functions in NodeJS calling ECS", + "description": "Orchestrate long-running ECS Fargate tasks using Lambda durable functions with callback pattern", + "language": "Node.js", + "level": "200", + "framework": "SAM", + "introBox": { + "headline": "How it works", + "text": [ + "This pattern demonstrates how to use AWS Lambda durable functions to orchestrate Amazon ECS Fargate tasks that can run for up to 24 hours.", + "The Lambda function creates a callback ID, starts an ECS task with that ID, and suspends execution without incurring compute charges during the wait period.", + "When the ECS task completes, it calls the Lambda SendDurableExecutionCallbackSuccess API to resume the durable function and return results.", + "This pattern is ideal for long-running batch jobs, data processing, ML training, or any workload that exceeds Lambda's 15-minute timeout." + ] + }, + "gitHub": { + "template": { + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/lambda-durable-functions-nodejs-calling-ecs", + "templateURL": "serverless-patterns/lambda-durable-functions-nodejs-calling-ecs", + "projectFolder": "lambda-durable-functions-nodejs-calling-ecs", + "templateFile": "template.yaml" + } + }, + "resources": { + "bullets": [ + { + "text": "AWS Lambda durable functions Documentation", + "link": "https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html" + }, + { + "text": "Amazon ECS on AWS Fargate", + "link": "https://docs.aws.amazon.com/AmazonECS/latest/developerguide/AWS_Fargate.html" + }, + { + "text": "Lambda Durable Execution SDK for JavaScript", + "link": "https://www.npmjs.com/package/@aws/durable-execution-sdk-js" + }, + { + "text": "SendDurableExecutionCallbackSuccess API", + "link": "https://docs.aws.amazon.com/lambda/latest/api/API_SendDurableExecutionCallbackSuccess.html" + } + ] + }, + "deploy": { + "text": [ + "sam build", + "sam deploy --guided" + ] + }, + "testing": { + "text": [ + "See the GitHub repo for detailed testing instructions." + ] + }, + "cleanup": { + "text": [ + "sam delete" + ] + }, + "authors": [ + { + "name": "Surya Sai D", + "image": "", + "bio": "Surya works as a Technical Account Manager in AWS. He is an expert in Serverless frameworks and Event Driven Architectures. Surya is also passionate on technical writing and has contributed to AWS blogs and other Open Source Content.", + "linkedin": "surya-sai-d-64920416a" + } + ] +} diff --git a/lambda-durable-functions-nodejs-calling-ecs/src/callback-handler.js b/lambda-durable-functions-nodejs-calling-ecs/src/callback-handler.js new file mode 100644 index 000000000..1a8f527fe --- /dev/null +++ b/lambda-durable-functions-nodejs-calling-ecs/src/callback-handler.js @@ -0,0 +1,95 @@ +const { ECSClient, RunTaskCommand } = require('@aws-sdk/client-ecs'); +const { withDurableExecution } = require('@aws/durable-execution-sdk-js'); + +const ecs = new ECSClient({ region: process.env.AWS_REGION }); + +/** + * Lambda Durable Function - Callback Pattern + * + * This function demonstrates the callback pattern where: + * 1. Lambda creates a callback and gets a callback ID + * 2. Lambda starts an ECS task and passes the callback ID + * 3. Lambda waits for the callback (suspends without charges) + * 4. ECS task calls Lambda APIs directly to send success/failure + * 5. Lambda resumes and returns the result + */ +exports.handler = withDurableExecution(async (event, context) => { + console.log('Starting Lambda Durable Function - Callback Pattern'); + console.log('Event:', JSON.stringify(event)); + + const message = event.message || 'Hello from Lambda Durable Function'; + const processingTime = event.processingTime || 10; + + try { + // Use waitForCallback to create callback and start ECS task + const result = await context.waitForCallback( + 'ecs-task-callback', + async (callbackId) => { + console.log('Callback ID created:', callbackId); + console.log('Starting ECS task with callback ID...'); + + // Start ECS task with callback ID as environment variable + const runTaskParams = { + cluster: process.env.ECS_CLUSTER, + taskDefinition: process.env.ECS_TASK_DEFINITION, + launchType: 'FARGATE', + networkConfiguration: { + awsvpcConfiguration: { + subnets: process.env.ECS_SUBNETS.split(','), + securityGroups: [process.env.ECS_SECURITY_GROUP], + assignPublicIp: 'ENABLED' + } + }, + overrides: { + containerOverrides: [ + { + name: 'worker', + environment: [ + { name: 'CALLBACK_ID', value: callbackId }, + { name: 'MESSAGE', value: message }, + { name: 'PROCESSING_TIME', value: processingTime.toString() } + ] + } + ] + } + }; + + const response = await ecs.send(new RunTaskCommand(runTaskParams)); + + if (!response.tasks || response.tasks.length === 0) { + throw new Error('Failed to start ECS task'); + } + + const taskArn = response.tasks[0].taskArn; + console.log('ECS task started:', taskArn); + }, + { + timeout: { hours: 1 }, // Wait up to 1 hour for callback + heartbeatTimeout: { minutes: 5 } // Expect heartbeat every 5 minutes + } + ); + + console.log('Callback received with result:', result); + + return { + statusCode: 200, + body: JSON.stringify({ + message: 'ECS task completed successfully', + result: result, + pattern: 'callback' + }) + }; + + } catch (error) { + console.error('Error in durable function:', error); + + return { + statusCode: 500, + body: JSON.stringify({ + message: 'ECS task failed', + error: error.message, + pattern: 'callback' + }) + }; + } +}); diff --git a/lambda-durable-functions-nodejs-calling-ecs/src/package.json b/lambda-durable-functions-nodejs-calling-ecs/src/package.json new file mode 100644 index 000000000..dbca6cf8d --- /dev/null +++ b/lambda-durable-functions-nodejs-calling-ecs/src/package.json @@ -0,0 +1,23 @@ +{ + "name": "lambda-ecs-durable-nodejs", + "version": "1.0.0", + "description": "Lambda Durable Functions calling ECS with Node.js", + "main": "callback-handler.js", + "dependencies": { + "@aws-sdk/client-ecs": "^3.700.0", + "@aws-sdk/client-lambda": "^3.700.0", + "@aws/durable-execution-sdk-js": "^1.0.0" + }, + "devDependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [ + "lambda", + "durable", + "ecs", + "nodejs" + ], + "author": "", + "license": "MIT-0" +} diff --git a/lambda-durable-functions-nodejs-calling-ecs/src/polling-handler.js b/lambda-durable-functions-nodejs-calling-ecs/src/polling-handler.js new file mode 100644 index 000000000..7f22bf984 --- /dev/null +++ b/lambda-durable-functions-nodejs-calling-ecs/src/polling-handler.js @@ -0,0 +1,79 @@ +const { withDurableExecution } = require('@aws/durable-execution-sdk-js'); +const { ECSClient, RunTaskCommand, DescribeTasksCommand } = require('@aws-sdk/client-ecs'); + +const ecs = new ECSClient({}); + +exports.handler = withDurableExecution(async (event, context) => { + console.log('Starting Lambda Durable Function - Polling Pattern'); + console.log('Event:', JSON.stringify(event)); + + const { message = 'Default message', processingTime = 10 } = event; + + // Step 1: Start ECS task (checkpointed) + const taskInfo = await context.step('start-ecs-task', async () => { + const params = { + cluster: process.env.ECS_CLUSTER, + taskDefinition: process.env.ECS_TASK_DEFINITION, + launchType: 'FARGATE', + networkConfiguration: { + awsvpcConfiguration: { + subnets: [process.env.ECS_SUBNET_1, process.env.ECS_SUBNET_2], + assignPublicIp: 'ENABLED' + } + }, + overrides: { + containerOverrides: [{ + name: 'worker', + environment: [ + { name: 'MESSAGE', value: message }, + { name: 'PROCESSING_TIME', value: String(processingTime) } + ] + }] + } + }; + + console.log('Starting ECS task...'); + const response = await ecs.send(new RunTaskCommand(params)); + const taskArn = response.tasks[0].taskArn; + console.log('ECS task started:', taskArn); + return { taskArn, cluster: process.env.ECS_CLUSTER }; + }); + + console.log('Task started:', taskInfo.taskArn); + + // Step 2: Poll until complete (checkpointed) + const result = await context.step('poll-until-complete', async () => { + let attempts = 0; + const maxAttempts = 60; + + while (attempts < maxAttempts) { + await new Promise(r => setTimeout(r, 5000)); + + const response = await ecs.send(new DescribeTasksCommand({ + cluster: taskInfo.cluster, + tasks: [taskInfo.taskArn] + })); + + const task = response.tasks[0]; + console.log(`Poll attempt ${attempts + 1}: Status = ${task.lastStatus}`); + + if (task.lastStatus === 'STOPPED') { + const exitCode = task.containers[0].exitCode; + console.log(`Task stopped with exit code: ${exitCode}`); + + if (exitCode === 0) { + return { success: true, message: 'Task completed successfully', taskArn: taskInfo.taskArn }; + } else { + throw new Error(`Task failed with exit code: ${exitCode}`); + } + } + + attempts++; + } + + throw new Error('Polling timeout - task did not complete'); + }); + + console.log('Workflow completed:', JSON.stringify(result)); + return result; +}); diff --git a/lambda-durable-functions-nodejs-calling-ecs/template.yaml b/lambda-durable-functions-nodejs-calling-ecs/template.yaml new file mode 100644 index 000000000..30615f889 --- /dev/null +++ b/lambda-durable-functions-nodejs-calling-ecs/template.yaml @@ -0,0 +1,311 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: > + Lambda Durable Functions to ECS with Node.js - Callback Pattern + + This pattern demonstrates Lambda Durable Functions invoking ECS tasks using the callback pattern. + The ECS task directly calls Lambda APIs (SendDurableExecutionCallbackSuccess/Failure) instead of using DynamoDB. + +Parameters: + VpcCIDR: + Type: String + Default: 10.0.0.0/16 + Description: CIDR block for VPC + +Globals: + Function: + Timeout: 900 + MemorySize: 512 + Runtime: nodejs22.x + Architectures: + - arm64 + +Resources: + # VPC Configuration + VPC: + Type: AWS::EC2::VPC + Properties: + CidrBlock: !Ref VpcCIDR + EnableDnsHostnames: true + EnableDnsSupport: true + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-vpc + + PublicSubnet1: + Type: AWS::EC2::Subnet + Properties: + VpcId: !Ref VPC + CidrBlock: !Select [0, !Cidr [!Ref VpcCIDR, 4, 8]] + AvailabilityZone: !Select [0, !GetAZs ''] + MapPublicIpOnLaunch: true + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-public-1 + + PublicSubnet2: + Type: AWS::EC2::Subnet + Properties: + VpcId: !Ref VPC + CidrBlock: !Select [1, !Cidr [!Ref VpcCIDR, 4, 8]] + AvailabilityZone: !Select [1, !GetAZs ''] + MapPublicIpOnLaunch: true + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-public-2 + + InternetGateway: + Type: AWS::EC2::InternetGateway + Properties: + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-igw + + AttachGateway: + Type: AWS::EC2::VPCGatewayAttachment + Properties: + VpcId: !Ref VPC + InternetGatewayId: !Ref InternetGateway + + PublicRouteTable: + Type: AWS::EC2::RouteTable + Properties: + VpcId: !Ref VPC + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-public-rt + + PublicRoute: + Type: AWS::EC2::Route + DependsOn: AttachGateway + Properties: + RouteTableId: !Ref PublicRouteTable + DestinationCidrBlock: 0.0.0.0/0 + GatewayId: !Ref InternetGateway + + SubnetRouteTableAssociation1: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + SubnetId: !Ref PublicSubnet1 + RouteTableId: !Ref PublicRouteTable + + SubnetRouteTableAssociation2: + Type: AWS::EC2::SubnetRouteTableAssociation + Properties: + SubnetId: !Ref PublicSubnet2 + RouteTableId: !Ref PublicRouteTable + + ECSSecurityGroup: + Type: AWS::EC2::SecurityGroup + Properties: + GroupDescription: Security group for ECS tasks + VpcId: !Ref VPC + SecurityGroupEgress: + - IpProtocol: -1 + CidrIp: 0.0.0.0/0 + Tags: + - Key: Name + Value: !Sub ${AWS::StackName}-ecs-sg + + # ECS Cluster + ECSCluster: + Type: AWS::ECS::Cluster + Properties: + ClusterName: !Sub ${AWS::StackName}-cluster + ClusterSettings: + - Name: containerInsights + Value: enabled + + # CloudWatch Log Group + ECSLogGroup: + Type: AWS::Logs::LogGroup + Properties: + LogGroupName: !Sub /ecs/${AWS::StackName} + RetentionInDays: 7 + + # ECS Task Execution Role + ECSTaskExecutionRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: ecs-tasks.amazonaws.com + Action: sts:AssumeRole + ManagedPolicyArns: + - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy + Policies: + - PolicyName: CloudWatchLogs + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - logs:CreateLogStream + - logs:PutLogEvents + Resource: !GetAtt ECSLogGroup.Arn + + # ECS Task Role (for Lambda callback APIs) + ECSTaskRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Service: ecs-tasks.amazonaws.com + Action: sts:AssumeRole + Policies: + - PolicyName: LambdaCallbackPolicy + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - lambda:SendDurableExecutionCallbackSuccess + - lambda:SendDurableExecutionCallbackFailure + - lambda:SendDurableExecutionCallbackHeartbeat + Resource: '*' + + # ECS Task Definition with Inline Node.js Code + ECSTaskDefinition: + Type: AWS::ECS::TaskDefinition + Properties: + Family: !Sub ${AWS::StackName}-task + NetworkMode: awsvpc + RequiresCompatibilities: + - FARGATE + Cpu: '256' + Memory: '512' + ExecutionRoleArn: !GetAtt ECSTaskExecutionRole.Arn + TaskRoleArn: !GetAtt ECSTaskRole.Arn + ContainerDefinitions: + - Name: worker + Image: public.ecr.aws/docker/library/python:3.12-alpine + Essential: true + EntryPoint: ["/bin/sh", "-c"] + Command: + - | + python3 -u -c " + import os, time, sys + print('=== ECS Task Started ===', flush=True) + print(f'Callback ID: {os.environ.get(\"CALLBACK_ID\", \"N/A\")}', flush=True) + print(f'Message: {os.environ.get(\"MESSAGE\", \"N/A\")}', flush=True) + print(f'Processing Time: {os.environ.get(\"PROCESSING_TIME\", \"10\")} seconds', flush=True) + print('', flush=True) + print('Simulating work...', flush=True) + time.sleep(int(os.environ.get('PROCESSING_TIME', '10'))) + print('', flush=True) + print('=== Task Completed Successfully ===', flush=True) + print('Result: {\"status\":\"completed\",\"message\":\"Processed: ' + os.environ.get('MESSAGE', '') + '\"}', flush=True) + print('', flush=True) + print('Note: In production, call Lambda SendDurableExecutionCallbackSuccess API here', flush=True) + print('Command: aws lambda send-durable-execution-callback-success --callback-id $CALLBACK_ID --result {...}', flush=True) + sys.exit(0) + " + LogConfiguration: + LogDriver: awslogs + Options: + awslogs-group: !Ref ECSLogGroup + awslogs-region: !Ref AWS::Region + awslogs-stream-prefix: ecs + + # Lambda Durable Function - Callback Pattern + CallbackLambdaFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: ./src + Handler: callback-handler.handler + Environment: + Variables: + ECS_CLUSTER: !Ref ECSCluster + ECS_TASK_DEFINITION: !Ref ECSTaskDefinition + ECS_SUBNETS: !Sub ${PublicSubnet1},${PublicSubnet2} + ECS_SECURITY_GROUP: !Ref ECSSecurityGroup + Policies: + - Statement: + - Effect: Allow + Action: + - ecs:RunTask + - ecs:DescribeTasks + Resource: '*' + - Effect: Allow + Action: + - iam:PassRole + Resource: + - !GetAtt ECSTaskExecutionRole.Arn + - !GetAtt ECSTaskRole.Arn + - Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Resource: '*' + AutoPublishAlias: prod + DurableConfig: + ExecutionTimeout: 86400 + RetentionPeriodInDays: 7 + + # Lambda Durable Function - Polling Pattern + PollingLambdaFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: ./src + Handler: polling-handler.handler + Environment: + Variables: + ECS_CLUSTER: !Ref ECSCluster + ECS_TASK_DEFINITION: !Ref ECSTaskDefinition + ECS_SUBNETS: !Sub ${PublicSubnet1},${PublicSubnet2} + ECS_SECURITY_GROUP: !Ref ECSSecurityGroup + Policies: + - Statement: + - Effect: Allow + Action: + - ecs:RunTask + - ecs:DescribeTasks + Resource: '*' + - Effect: Allow + Action: + - iam:PassRole + Resource: + - !GetAtt ECSTaskExecutionRole.Arn + - !GetAtt ECSTaskRole.Arn + - Effect: Allow + Action: + - logs:CreateLogGroup + - logs:CreateLogStream + - logs:PutLogEvents + Resource: '*' + AutoPublishAlias: prod + DurableConfig: + ExecutionTimeout: 86400 + RetentionPeriodInDays: 7 + +Outputs: + CallbackLambdaFunctionArn: + Description: ARN of the Callback Lambda Durable Function + Value: !GetAtt CallbackLambdaFunction.Arn + + PollingLambdaFunctionArn: + Description: ARN of the Polling Lambda Durable Function + Value: !GetAtt PollingLambdaFunction.Arn + + ECSClusterName: + Description: Name of the ECS Cluster + Value: !Ref ECSCluster + + ECSTaskDefinitionArn: + Description: ARN of the ECS Task Definition + Value: !Ref ECSTaskDefinition + + LogGroupName: + Description: CloudWatch Log Group for ECS tasks + Value: !Ref ECSLogGroup + + VPCId: + Description: VPC ID + Value: !Ref VPC From 8bd1679d409db6fb5c819a657d881019e7ce1310 Mon Sep 17 00:00:00 2001 From: dsiz Date: Sun, 22 Feb 2026 15:36:58 +0530 Subject: [PATCH 2/8] Remove polling pattern, keep only callback approach for ECS integration --- .../src/polling-handler.js | 79 ------------------- 1 file changed, 79 deletions(-) delete mode 100644 lambda-durable-functions-nodejs-calling-ecs/src/polling-handler.js diff --git a/lambda-durable-functions-nodejs-calling-ecs/src/polling-handler.js b/lambda-durable-functions-nodejs-calling-ecs/src/polling-handler.js deleted file mode 100644 index 7f22bf984..000000000 --- a/lambda-durable-functions-nodejs-calling-ecs/src/polling-handler.js +++ /dev/null @@ -1,79 +0,0 @@ -const { withDurableExecution } = require('@aws/durable-execution-sdk-js'); -const { ECSClient, RunTaskCommand, DescribeTasksCommand } = require('@aws-sdk/client-ecs'); - -const ecs = new ECSClient({}); - -exports.handler = withDurableExecution(async (event, context) => { - console.log('Starting Lambda Durable Function - Polling Pattern'); - console.log('Event:', JSON.stringify(event)); - - const { message = 'Default message', processingTime = 10 } = event; - - // Step 1: Start ECS task (checkpointed) - const taskInfo = await context.step('start-ecs-task', async () => { - const params = { - cluster: process.env.ECS_CLUSTER, - taskDefinition: process.env.ECS_TASK_DEFINITION, - launchType: 'FARGATE', - networkConfiguration: { - awsvpcConfiguration: { - subnets: [process.env.ECS_SUBNET_1, process.env.ECS_SUBNET_2], - assignPublicIp: 'ENABLED' - } - }, - overrides: { - containerOverrides: [{ - name: 'worker', - environment: [ - { name: 'MESSAGE', value: message }, - { name: 'PROCESSING_TIME', value: String(processingTime) } - ] - }] - } - }; - - console.log('Starting ECS task...'); - const response = await ecs.send(new RunTaskCommand(params)); - const taskArn = response.tasks[0].taskArn; - console.log('ECS task started:', taskArn); - return { taskArn, cluster: process.env.ECS_CLUSTER }; - }); - - console.log('Task started:', taskInfo.taskArn); - - // Step 2: Poll until complete (checkpointed) - const result = await context.step('poll-until-complete', async () => { - let attempts = 0; - const maxAttempts = 60; - - while (attempts < maxAttempts) { - await new Promise(r => setTimeout(r, 5000)); - - const response = await ecs.send(new DescribeTasksCommand({ - cluster: taskInfo.cluster, - tasks: [taskInfo.taskArn] - })); - - const task = response.tasks[0]; - console.log(`Poll attempt ${attempts + 1}: Status = ${task.lastStatus}`); - - if (task.lastStatus === 'STOPPED') { - const exitCode = task.containers[0].exitCode; - console.log(`Task stopped with exit code: ${exitCode}`); - - if (exitCode === 0) { - return { success: true, message: 'Task completed successfully', taskArn: taskInfo.taskArn }; - } else { - throw new Error(`Task failed with exit code: ${exitCode}`); - } - } - - attempts++; - } - - throw new Error('Polling timeout - task did not complete'); - }); - - console.log('Workflow completed:', JSON.stringify(result)); - return result; -}); From 7cb803808a9f630088fb60f33998fe8a1ace4436 Mon Sep 17 00:00:00 2001 From: dsiz Date: Sun, 22 Feb 2026 15:45:43 +0530 Subject: [PATCH 3/8] Applied PR #2959 feedback and removed polling pattern and other concerns --- .../README.md | 2 +- .../template.yaml | 50 ++----------------- 2 files changed, 6 insertions(+), 46 deletions(-) diff --git a/lambda-durable-functions-nodejs-calling-ecs/README.md b/lambda-durable-functions-nodejs-calling-ecs/README.md index 25b4c04bf..31e679a9d 100644 --- a/lambda-durable-functions-nodejs-calling-ecs/README.md +++ b/lambda-durable-functions-nodejs-calling-ecs/README.md @@ -35,7 +35,7 @@ The pattern uses Lambda durable functions with the callback pattern to orchestra * [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured * [AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) installed -* Node.js 22.x runtime (automatically provided by Lambda) +* Node.js runtime (see [supported runtimes for durable functions](https://docs.aws.amazon.com/lambda/latest/dg/durable-supported-runtimes.html)) ## Deployment diff --git a/lambda-durable-functions-nodejs-calling-ecs/template.yaml b/lambda-durable-functions-nodejs-calling-ecs/template.yaml index 30615f889..33fc95ca1 100644 --- a/lambda-durable-functions-nodejs-calling-ecs/template.yaml +++ b/lambda-durable-functions-nodejs-calling-ecs/template.yaml @@ -1,9 +1,9 @@ AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: > - Lambda Durable Functions to ECS with Node.js - Callback Pattern + Lambda durable functions to ECS with Node.js - Callback Pattern - This pattern demonstrates Lambda Durable Functions invoking ECS tasks using the callback pattern. + This pattern demonstrates Lambda durable functions invoking ECS tasks using the callback pattern. The ECS task directly calls Lambda APIs (SendDurableExecutionCallbackSuccess/Failure) instead of using DynamoDB. Parameters: @@ -231,7 +231,7 @@ Resources: Action: - ecs:RunTask - ecs:DescribeTasks - Resource: '*' + Resource: !Sub 'arn:aws:ecs:${AWS::Region}:${AWS::AccountId}:*' - Effect: Allow Action: - iam:PassRole @@ -243,43 +243,7 @@ Resources: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents - Resource: '*' - AutoPublishAlias: prod - DurableConfig: - ExecutionTimeout: 86400 - RetentionPeriodInDays: 7 - - # Lambda Durable Function - Polling Pattern - PollingLambdaFunction: - Type: AWS::Serverless::Function - Properties: - CodeUri: ./src - Handler: polling-handler.handler - Environment: - Variables: - ECS_CLUSTER: !Ref ECSCluster - ECS_TASK_DEFINITION: !Ref ECSTaskDefinition - ECS_SUBNETS: !Sub ${PublicSubnet1},${PublicSubnet2} - ECS_SECURITY_GROUP: !Ref ECSSecurityGroup - Policies: - - Statement: - - Effect: Allow - Action: - - ecs:RunTask - - ecs:DescribeTasks - Resource: '*' - - Effect: Allow - Action: - - iam:PassRole - Resource: - - !GetAtt ECSTaskExecutionRole.Arn - - !GetAtt ECSTaskRole.Arn - - Effect: Allow - Action: - - logs:CreateLogGroup - - logs:CreateLogStream - - logs:PutLogEvents - Resource: '*' + Resource: !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:*' AutoPublishAlias: prod DurableConfig: ExecutionTimeout: 86400 @@ -287,13 +251,9 @@ Resources: Outputs: CallbackLambdaFunctionArn: - Description: ARN of the Callback Lambda Durable Function + Description: ARN of the Callback Lambda durable function Value: !GetAtt CallbackLambdaFunction.Arn - PollingLambdaFunctionArn: - Description: ARN of the Polling Lambda Durable Function - Value: !GetAtt PollingLambdaFunction.Arn - ECSClusterName: Description: Name of the ECS Cluster Value: !Ref ECSCluster From dc9dd7b1f3f8e063646137ca54dbc23d388038d0 Mon Sep 17 00:00:00 2001 From: dsiz Date: Sun, 22 Feb 2026 15:58:16 +0530 Subject: [PATCH 4/8] Applied all PR #2959 feedback --- lambda-durable-functions-nodejs-calling-ecs/README.md | 6 +++--- .../example-pattern.json | 8 ++++---- .../src/callback-handler.js | 6 +++--- .../src/package.json | 2 +- lambda-durable-functions-nodejs-calling-ecs/template.yaml | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/lambda-durable-functions-nodejs-calling-ecs/README.md b/lambda-durable-functions-nodejs-calling-ecs/README.md index 31e679a9d..4a6772310 100644 --- a/lambda-durable-functions-nodejs-calling-ecs/README.md +++ b/lambda-durable-functions-nodejs-calling-ecs/README.md @@ -76,7 +76,7 @@ aws lambda invoke \ response.json ``` -**Note:** The `:prod` alias is required for durable functions. +**Note:** A qualified ARN (version or alias) is required for durable functions. See [invoking durable functions](https://docs.aws.amazon.com/lambda/latest/dg/durable-invoking.html#durable-invoking-qualified-arns). ### Monitor Execution @@ -151,8 +151,8 @@ aws lambda send-durable-execution-callback-success \ ### Key Configuration **Lambda Function:** -- Runtime: `nodejs22.x` (required for durable functions) -- `AutoPublishAlias: prod` (required) +- Runtime: `nodejs22.x` (see [supported runtimes](https://docs.aws.amazon.com/lambda/latest/dg/durable-supported-runtimes.html)) +- `AutoPublishAlias: prod` - `DurableConfig` with execution timeout and retention period **ECS Task:** diff --git a/lambda-durable-functions-nodejs-calling-ecs/example-pattern.json b/lambda-durable-functions-nodejs-calling-ecs/example-pattern.json index a1bc77d31..3763fbd0a 100644 --- a/lambda-durable-functions-nodejs-calling-ecs/example-pattern.json +++ b/lambda-durable-functions-nodejs-calling-ecs/example-pattern.json @@ -3,12 +3,12 @@ "description": "Orchestrate long-running ECS Fargate tasks using Lambda durable functions with callback pattern", "language": "Node.js", "level": "200", - "framework": "SAM", + "framework": "AWS SAM", "introBox": { "headline": "How it works", "text": [ "This pattern demonstrates how to use AWS Lambda durable functions to orchestrate Amazon ECS Fargate tasks that can run for up to 24 hours.", - "The Lambda function creates a callback ID, starts an ECS task with that ID, and suspends execution without incurring compute charges during the wait period.", + "The Lambda function creates a callback ID, starts an ECS task with that ID, and then automatically suspends execution without incurring compute charges during the wait period.", "When the ECS task completes, it calls the Lambda SendDurableExecutionCallbackSuccess API to resume the durable function and return results.", "This pattern is ideal for long-running batch jobs, data processing, ML training, or any workload that exceeds Lambda's 15-minute timeout." ] @@ -54,14 +54,14 @@ }, "cleanup": { "text": [ - "sam delete" + "sam delete" ] }, "authors": [ { "name": "Surya Sai D", "image": "", - "bio": "Surya works as a Technical Account Manager in AWS. He is an expert in Serverless frameworks and Event Driven Architectures. Surya is also passionate on technical writing and has contributed to AWS blogs and other Open Source Content.", + "bio": "Surya works as a Technical Account Manager at AWS. He is an expert in Serverless frameworks and Event Driven Architectures. Surya is also passionate on technical writing and has contributed to AWS blogs and other Open Source Content.", "linkedin": "surya-sai-d-64920416a" } ] diff --git a/lambda-durable-functions-nodejs-calling-ecs/src/callback-handler.js b/lambda-durable-functions-nodejs-calling-ecs/src/callback-handler.js index 1a8f527fe..8a66e9317 100644 --- a/lambda-durable-functions-nodejs-calling-ecs/src/callback-handler.js +++ b/lambda-durable-functions-nodejs-calling-ecs/src/callback-handler.js @@ -4,7 +4,7 @@ const { withDurableExecution } = require('@aws/durable-execution-sdk-js'); const ecs = new ECSClient({ region: process.env.AWS_REGION }); /** - * Lambda Durable Function - Callback Pattern + * Lambda durable function - Callback Pattern * * This function demonstrates the callback pattern where: * 1. Lambda creates a callback and gets a callback ID @@ -14,10 +14,10 @@ const ecs = new ECSClient({ region: process.env.AWS_REGION }); * 5. Lambda resumes and returns the result */ exports.handler = withDurableExecution(async (event, context) => { - console.log('Starting Lambda Durable Function - Callback Pattern'); + console.log('Starting Lambda durable function - Callback Pattern'); console.log('Event:', JSON.stringify(event)); - const message = event.message || 'Hello from Lambda Durable Function'; + const message = event.message || 'Hello from Lambda durable function'; const processingTime = event.processingTime || 10; try { diff --git a/lambda-durable-functions-nodejs-calling-ecs/src/package.json b/lambda-durable-functions-nodejs-calling-ecs/src/package.json index dbca6cf8d..e0824d266 100644 --- a/lambda-durable-functions-nodejs-calling-ecs/src/package.json +++ b/lambda-durable-functions-nodejs-calling-ecs/src/package.json @@ -1,7 +1,7 @@ { "name": "lambda-ecs-durable-nodejs", "version": "1.0.0", - "description": "Lambda Durable Functions calling ECS with Node.js", + "description": "Lambda durable functions calling ECS with Node.js", "main": "callback-handler.js", "dependencies": { "@aws-sdk/client-ecs": "^3.700.0", diff --git a/lambda-durable-functions-nodejs-calling-ecs/template.yaml b/lambda-durable-functions-nodejs-calling-ecs/template.yaml index 33fc95ca1..077193bb7 100644 --- a/lambda-durable-functions-nodejs-calling-ecs/template.yaml +++ b/lambda-durable-functions-nodejs-calling-ecs/template.yaml @@ -213,7 +213,7 @@ Resources: awslogs-region: !Ref AWS::Region awslogs-stream-prefix: ecs - # Lambda Durable Function - Callback Pattern + # Lambda durable function - Callback Pattern CallbackLambdaFunction: Type: AWS::Serverless::Function Properties: From 3f357231d9fa98e6815a7e788c13b650d01cd7e5 Mon Sep 17 00:00:00 2001 From: dsiz Date: Sun, 22 Feb 2026 18:07:18 +0530 Subject: [PATCH 5/8] Change ECS to Amazon ECS in title --- .../example-pattern.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lambda-durable-functions-nodejs-calling-ecs/example-pattern.json b/lambda-durable-functions-nodejs-calling-ecs/example-pattern.json index 3763fbd0a..ef35632e4 100644 --- a/lambda-durable-functions-nodejs-calling-ecs/example-pattern.json +++ b/lambda-durable-functions-nodejs-calling-ecs/example-pattern.json @@ -1,5 +1,5 @@ { - "title": "AWS Lambda durable functions in NodeJS calling ECS", + "title": "AWS Lambda durable functions in NodeJS calling Amazon ECS", "description": "Orchestrate long-running ECS Fargate tasks using Lambda durable functions with callback pattern", "language": "Node.js", "level": "200", From 7d879644aa0a306689c471862617e24b8717bdbb Mon Sep 17 00:00:00 2001 From: dsiz Date: Mon, 23 Feb 2026 08:45:24 +0530 Subject: [PATCH 6/8] Replace console.log with context.logger per PR feedback --- .../src/callback-handler.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lambda-durable-functions-nodejs-calling-ecs/src/callback-handler.js b/lambda-durable-functions-nodejs-calling-ecs/src/callback-handler.js index 8a66e9317..8704e4785 100644 --- a/lambda-durable-functions-nodejs-calling-ecs/src/callback-handler.js +++ b/lambda-durable-functions-nodejs-calling-ecs/src/callback-handler.js @@ -14,8 +14,8 @@ const ecs = new ECSClient({ region: process.env.AWS_REGION }); * 5. Lambda resumes and returns the result */ exports.handler = withDurableExecution(async (event, context) => { - console.log('Starting Lambda durable function - Callback Pattern'); - console.log('Event:', JSON.stringify(event)); + context.logger.info('Starting Lambda durable function - Callback Pattern'); + context.logger.info('Event:', JSON.stringify(event)); const message = event.message || 'Hello from Lambda durable function'; const processingTime = event.processingTime || 10; @@ -25,8 +25,8 @@ exports.handler = withDurableExecution(async (event, context) => { const result = await context.waitForCallback( 'ecs-task-callback', async (callbackId) => { - console.log('Callback ID created:', callbackId); - console.log('Starting ECS task with callback ID...'); + context.logger.info('Callback ID created:', callbackId); + context.logger.info('Starting ECS task with callback ID...'); // Start ECS task with callback ID as environment variable const runTaskParams = { @@ -61,7 +61,7 @@ exports.handler = withDurableExecution(async (event, context) => { } const taskArn = response.tasks[0].taskArn; - console.log('ECS task started:', taskArn); + context.logger.info('ECS task started:', taskArn); }, { timeout: { hours: 1 }, // Wait up to 1 hour for callback @@ -69,7 +69,7 @@ exports.handler = withDurableExecution(async (event, context) => { } ); - console.log('Callback received with result:', result); + context.logger.info('Callback received with result:', result); return { statusCode: 200, @@ -81,7 +81,7 @@ exports.handler = withDurableExecution(async (event, context) => { }; } catch (error) { - console.error('Error in durable function:', error); + context.logger.error('Error in durable function:', error); return { statusCode: 500, From f0d94af1eb494eee9c13d36146b7af441ff4e6ec Mon Sep 17 00:00:00 2001 From: dsiz Date: Mon, 23 Feb 2026 15:34:56 +0530 Subject: [PATCH 7/8] Remove Cost Considerations section per PR feedback --- lambda-durable-functions-nodejs-calling-ecs/README.md | 7 ------- 1 file changed, 7 deletions(-) diff --git a/lambda-durable-functions-nodejs-calling-ecs/README.md b/lambda-durable-functions-nodejs-calling-ecs/README.md index 4a6772310..b0bd956c7 100644 --- a/lambda-durable-functions-nodejs-calling-ecs/README.md +++ b/lambda-durable-functions-nodejs-calling-ecs/README.md @@ -202,13 +202,6 @@ Delete the stack: sam delete ``` -## Cost Considerations - -- **Lambda:** Charged only for active execution time, not during wait periods -- **ECS Fargate:** Charged per vCPU and memory per second while tasks run -- **CloudWatch Logs:** Charged for log ingestion and storage -- **VPC:** NAT Gateway charges if using private subnets (this pattern uses public subnets) - ## Additional Resources - [AWS Lambda durable functions Documentation](https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html) From 8befcb242394c8b8256b193482326d49ec8b733b Mon Sep 17 00:00:00 2001 From: Ben <9841563+bfreiberg@users.noreply.github.com> Date: Mon, 23 Feb 2026 11:32:52 +0100 Subject: [PATCH 8/8] Add final pattern file --- ...-durable-functions-nodejs-calling-ecs.json | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 lambda-durable-functions-nodejs-calling-ecs/lambda-durable-functions-nodejs-calling-ecs.json diff --git a/lambda-durable-functions-nodejs-calling-ecs/lambda-durable-functions-nodejs-calling-ecs.json b/lambda-durable-functions-nodejs-calling-ecs/lambda-durable-functions-nodejs-calling-ecs.json new file mode 100644 index 000000000..68b0c87d7 --- /dev/null +++ b/lambda-durable-functions-nodejs-calling-ecs/lambda-durable-functions-nodejs-calling-ecs.json @@ -0,0 +1,87 @@ +{ + "title": "AWS Lambda durable functions in NodeJS calling Amazon ECS", + "description": "Orchestrate long-running ECS Fargate tasks using Lambda durable functions with callback pattern", + "language": "Node.js", + "level": "200", + "framework": "AWS SAM", + "introBox": { + "headline": "How it works", + "text": [ + "This pattern demonstrates how to use AWS Lambda durable functions to orchestrate Amazon ECS Fargate tasks that can run for up to 24 hours.", + "The Lambda function creates a callback ID, starts an ECS task with that ID, and then automatically suspends execution without incurring compute charges during the wait period.", + "When the ECS task completes, it calls the Lambda SendDurableExecutionCallbackSuccess API to resume the durable function and return results.", + "This pattern is ideal for long-running batch jobs, data processing, ML training, or any workload that exceeds Lambda's 15-minute timeout." + ] + }, + "gitHub": { + "template": { + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/lambda-durable-functions-nodejs-calling-ecs", + "templateURL": "serverless-patterns/lambda-durable-functions-nodejs-calling-ecs", + "projectFolder": "lambda-durable-functions-nodejs-calling-ecs", + "templateFile": "template.yaml" + } + }, + "resources": { + "bullets": [ + { + "text": "AWS Lambda durable functions Documentation", + "link": "https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html" + }, + { + "text": "Amazon ECS on AWS Fargate", + "link": "https://docs.aws.amazon.com/AmazonECS/latest/developerguide/AWS_Fargate.html" + }, + { + "text": "Lambda Durable Execution SDK for JavaScript", + "link": "https://www.npmjs.com/package/@aws/durable-execution-sdk-js" + }, + { + "text": "SendDurableExecutionCallbackSuccess API", + "link": "https://docs.aws.amazon.com/lambda/latest/api/API_SendDurableExecutionCallbackSuccess.html" + } + ] + }, + "deploy": { + "text": [ + "sam build", + "sam deploy --guided" + ] + }, + "testing": { + "text": [ + "See the GitHub repo for detailed testing instructions." + ] + }, + "cleanup": { + "text": [ + "sam delete" + ] + }, + "authors": [ + { + "name": "Surya Sai D", + "image": "", + "bio": "Surya works as a Technical Account Manager at AWS. He is an expert in Serverless frameworks and Event Driven Architectures. Surya is also passionate on technical writing and has contributed to AWS blogs and other Open Source Content.", + "linkedin": "surya-sai-d-64920416a" + } + ], + "patternArch": { + "icon1": { + "x": 20, + "y": 50, + "service": "lambda", + "label": "AWS Lambda durable functions" + }, + "icon2": { + "x": 80, + "y": 50, + "service": "ecs", + "label": "Amazon ESC task" + }, + "line1": { + "from": "icon1", + "to": "icon2", + "label": "wait for callback" + } + } +}