|
| 1 | +# AWS Lambda durable functions with Amazon ECS Integration |
| 2 | + |
| 3 | +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. |
| 4 | + |
| 5 | +**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. |
| 6 | + |
| 7 | +Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/lambda-durable-functions-nodejs-calling-ecs |
| 8 | + |
| 9 | +## Architecture |
| 10 | + |
| 11 | + |
| 12 | + |
| 13 | +The pattern uses Lambda durable functions with the callback pattern to orchestrate ECS Fargate tasks cost-effectively. |
| 14 | + |
| 15 | +### Workflow Steps |
| 16 | + |
| 17 | +1. **Lambda function invoked** with task parameters (message, processing time) |
| 18 | +2. **Durable function creates callback ID** using `context.waitForCallback()` |
| 19 | +3. **ECS Fargate task started** with callback ID passed as environment variable |
| 20 | +4. **Lambda function pauses** (no compute charges during wait) |
| 21 | +5. **ECS task processes workload** and logs progress to CloudWatch |
| 22 | +6. **ECS task completes** (in production, would call `SendDurableExecutionCallbackSuccess`) |
| 23 | +7. **Lambda function resumes** and returns result |
| 24 | + |
| 25 | +## Key Features |
| 26 | + |
| 27 | +- ✅ **24-Hour Wait Time** - Can wait up to 24 hours for ECS task completion |
| 28 | +- ✅ **No Compute Charges During Wait** - Function suspended during wait period |
| 29 | +- ✅ **Callback Pattern** - ECS tasks call Lambda APIs directly to resume execution |
| 30 | +- ✅ **CloudWatch Logs** - Full visibility into both Lambda and ECS execution |
| 31 | +- ✅ **Generic Container** - Uses public Python image, easily replaceable |
| 32 | +- ✅ **Fargate Serverless** - No EC2 instances to manage |
| 33 | + |
| 34 | +## Prerequisites |
| 35 | + |
| 36 | +* [AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/install-cliv2.html) installed and configured |
| 37 | +* [AWS SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) installed |
| 38 | +* Node.js runtime (see [supported runtimes for durable functions](https://docs.aws.amazon.com/lambda/latest/dg/durable-supported-runtimes.html)) |
| 39 | + |
| 40 | +## Deployment |
| 41 | + |
| 42 | +1. Navigate to the pattern directory: |
| 43 | + ```bash |
| 44 | + cd lambda-durable-functions-nodejs-calling-ecs |
| 45 | + ``` |
| 46 | + |
| 47 | +2. Build the SAM application: |
| 48 | + ```bash |
| 49 | + sam build |
| 50 | + ``` |
| 51 | + |
| 52 | +3. Deploy the application: |
| 53 | + ```bash |
| 54 | + sam deploy --guided |
| 55 | + ``` |
| 56 | + |
| 57 | + During the guided deployment: |
| 58 | + - Accept default values or customize as needed |
| 59 | + - Allow SAM CLI to create IAM roles when prompted |
| 60 | + - Note the function name from the outputs |
| 61 | + |
| 62 | +4. Note the `CallbackFunctionName` from the CloudFormation outputs |
| 63 | + |
| 64 | +## Testing |
| 65 | + |
| 66 | +### Test the Callback Pattern |
| 67 | + |
| 68 | +Invoke the Lambda function with a test payload: |
| 69 | + |
| 70 | +```bash |
| 71 | +aws lambda invoke \ |
| 72 | + --function-name <CallbackFunctionName>:prod \ |
| 73 | + --invocation-type Event \ |
| 74 | + --payload '{"message":"Test ECS task","processingTime":8}' \ |
| 75 | + --cli-binary-format raw-in-base64-out \ |
| 76 | + response.json |
| 77 | +``` |
| 78 | + |
| 79 | +**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). |
| 80 | + |
| 81 | +### Monitor Execution |
| 82 | + |
| 83 | +Check Lambda logs: |
| 84 | +```bash |
| 85 | +aws logs tail /aws/lambda/<CallbackFunctionName> --since 2m --follow |
| 86 | +``` |
| 87 | + |
| 88 | +Check ECS task logs: |
| 89 | +```bash |
| 90 | +aws logs tail /ecs/lambda-ecs-durable-demo --since 2m --follow |
| 91 | +``` |
| 92 | + |
| 93 | +### Expected Output |
| 94 | + |
| 95 | +**Lambda Logs:** |
| 96 | +``` |
| 97 | +Starting Lambda durable function - Callback Pattern |
| 98 | +Callback ID created: <callback-id> |
| 99 | +Starting ECS task with callback ID... |
| 100 | +ECS task started: arn:aws:ecs:... |
| 101 | +``` |
| 102 | + |
| 103 | +**ECS Logs:** |
| 104 | +``` |
| 105 | +=== ECS Task Started === |
| 106 | +Callback ID: <callback-id> |
| 107 | +Message: Test ECS task |
| 108 | +Processing Time: 8 seconds |
| 109 | +Simulating work... |
| 110 | +=== Task Completed Successfully === |
| 111 | +Result: {"status":"completed","message":"Processed: Test ECS task"} |
| 112 | +Note: In production, call Lambda SendDurableExecutionCallbackSuccess API here |
| 113 | +``` |
| 114 | + |
| 115 | +## How It Works |
| 116 | + |
| 117 | +### Lambda durable function (Node.js) |
| 118 | + |
| 119 | +The Lambda function uses the `@aws/durable-execution-sdk-js` package: |
| 120 | + |
| 121 | +```javascript |
| 122 | +const { withDurableExecution } = require('@aws/durable-execution-sdk-js'); |
| 123 | + |
| 124 | +exports.handler = withDurableExecution(async (event, context) => { |
| 125 | + // Create callback and start ECS task |
| 126 | + const result = await context.waitForCallback( |
| 127 | + 'ecs-task-callback', |
| 128 | + async (callbackId) => { |
| 129 | + // Start ECS task with callback ID |
| 130 | + const response = await ecs.send(new RunTaskCommand({ |
| 131 | + // ... pass callbackId as environment variable |
| 132 | + })); |
| 133 | + }, |
| 134 | + { timeout: { hours: 1 } } |
| 135 | + ); |
| 136 | + |
| 137 | + return result; |
| 138 | +}); |
| 139 | +``` |
| 140 | + |
| 141 | +### ECS Task (Python) |
| 142 | + |
| 143 | +The ECS container receives the callback ID and processes the workload. In production, it would call the Lambda API: |
| 144 | + |
| 145 | +```bash |
| 146 | +aws lambda send-durable-execution-callback-success \ |
| 147 | + --callback-id $CALLBACK_ID \ |
| 148 | + --result '{"status":"completed","data":"..."}' |
| 149 | +``` |
| 150 | + |
| 151 | +### Key Configuration |
| 152 | + |
| 153 | +**Lambda Function:** |
| 154 | +- Runtime: `nodejs22.x` (see [supported runtimes](https://docs.aws.amazon.com/lambda/latest/dg/durable-supported-runtimes.html)) |
| 155 | +- `AutoPublishAlias: prod` |
| 156 | +- `DurableConfig` with execution timeout and retention period |
| 157 | + |
| 158 | +**ECS Task:** |
| 159 | +- Launch type: `FARGATE` |
| 160 | +- Public subnet with `assignPublicIp: ENABLED` |
| 161 | +- Container image: `public.ecr.aws/docker/library/python:3.12-alpine` |
| 162 | +- CloudWatch Logs enabled |
| 163 | + |
| 164 | +## Customization |
| 165 | + |
| 166 | +### Replace the ECS Container |
| 167 | + |
| 168 | +The pattern uses a generic Python container for demonstration. To use your own container: |
| 169 | + |
| 170 | +1. Update the `Image` in the `ECSTaskDefinition` resource |
| 171 | +2. Ensure your container: |
| 172 | + - Reads the `CALLBACK_ID` environment variable |
| 173 | + - Calls `aws lambda send-durable-execution-callback-success` on completion |
| 174 | + - Calls `aws lambda send-durable-execution-callback-failure` on error |
| 175 | + |
| 176 | +### Adjust Timeouts |
| 177 | + |
| 178 | +Modify the durable function timeout in `template.yaml`: |
| 179 | + |
| 180 | +```yaml |
| 181 | +DurableConfig: |
| 182 | + ExecutionTimeout: 86400 # 24 hours in seconds |
| 183 | + RetentionPeriodInDays: 7 |
| 184 | +``` |
| 185 | +
|
| 186 | +And the callback timeout in the handler: |
| 187 | +
|
| 188 | +```javascript |
| 189 | +context.waitForCallback('ecs-task-callback', async (callbackId) => { |
| 190 | + // ... |
| 191 | +}, { |
| 192 | + timeout: { hours: 24 }, // Maximum wait time |
| 193 | + heartbeatTimeout: { minutes: 5 } // Optional heartbeat |
| 194 | +}) |
| 195 | +``` |
| 196 | + |
| 197 | +## Cleanup |
| 198 | + |
| 199 | +Delete the stack: |
| 200 | + |
| 201 | +```bash |
| 202 | +sam delete |
| 203 | +``` |
| 204 | + |
| 205 | +## Additional Resources |
| 206 | + |
| 207 | +- [AWS Lambda durable functions Documentation](https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html) |
| 208 | +- [Amazon ECS on AWS Fargate](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/AWS_Fargate.html) |
| 209 | +- [AWS SAM Documentation](https://docs.aws.amazon.com/serverless-application-model/) |
| 210 | + |
| 211 | +--- |
| 212 | + |
| 213 | +© 2026 Amazon Web Services, Inc. or its affiliates. All Rights Reserved. |
0 commit comments