From addf48c049d88c479410ed29d8d0cf580ce0aced Mon Sep 17 00:00:00 2001 From: sahil bhimjiani Date: Fri, 6 Feb 2026 16:06:23 -0600 Subject: [PATCH 1/4] Feat lambda durable function chaining using SAM --- .../README.md | 150 ++++++++++++++++++ .../example-pattern.json | 78 +++++++++ .../src/orchestrator/app.py | 25 +++ .../src/orchestrator/requirements.txt | 1 + .../src/step1_add/app.py | 8 + .../src/step2_transform/app.py | 8 + .../src/step3_finalize/app.py | 8 + .../template.yaml | 74 +++++++++ 8 files changed, 352 insertions(+) create mode 100644 lambda-durable-function-chaining-sam/README.md create mode 100644 lambda-durable-function-chaining-sam/example-pattern.json create mode 100644 lambda-durable-function-chaining-sam/src/orchestrator/app.py create mode 100644 lambda-durable-function-chaining-sam/src/orchestrator/requirements.txt create mode 100644 lambda-durable-function-chaining-sam/src/step1_add/app.py create mode 100644 lambda-durable-function-chaining-sam/src/step2_transform/app.py create mode 100644 lambda-durable-function-chaining-sam/src/step3_finalize/app.py create mode 100644 lambda-durable-function-chaining-sam/template.yaml diff --git a/lambda-durable-function-chaining-sam/README.md b/lambda-durable-function-chaining-sam/README.md new file mode 100644 index 000000000..9b3960489 --- /dev/null +++ b/lambda-durable-function-chaining-sam/README.md @@ -0,0 +1,150 @@ +# Function Chaining with AWS Lambda Durable Functions + +This pattern demonstrates the **function chaining** workflow pattern using AWS Lambda durable functions. A durable orchestrator chains three Lambda functions sequentially, with automatic checkpointing after each step for fault tolerance. + +Learn more about this pattern at Serverless Land Patterns: https://serverlessland.com/patterns/lambda-durable-function-chaining-sam + +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. + +## 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 SAM CLI](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) installed (version 1.141.0+ with DurableConfig support) +* Python 3.13+ + +## Deployment Instructions + +1. Create a new directory, navigate to that directory in a terminal and clone the GitHub repository: + ```bash + git clone https://github.com/aws-samples/serverless-patterns + ``` +2. Change directory to the pattern directory: + ```bash + cd serverless-patterns/lambda-durable-function-chaining-sam + ``` +3. Build and deploy the application: + ```bash + sam build + sam deploy --guided + ``` +4. During the prompts: + * Enter a stack name + * Enter your preferred AWS Region + * Accept the defaults for remaining options + +## How it works + +This pattern implements the **function chaining** workflow pattern where a durable orchestrator invokes multiple Lambda functions in sequence, passing the output of each step as input to the next. + +### Architecture + +```mermaid +flowchart LR + A[Input] --> B[Durable Orchestrator] + B -->|context.invoke| C[Step 1: Add Data] + C -->|checkpoint| B + B -->|context.invoke| D[Step 2: Transform] + D -->|checkpoint| B + B -->|context.invoke| E[Step 3: Finalize] + E -->|checkpoint| B + B --> F[Output] + + subgraph Durable Function + B + end + + subgraph Regular Lambda Functions + C + D + E + end +``` + +The orchestrator uses `context.invoke()` to chain 3 Lambda functions with automatic checkpointing. + +### What are Lambda Durable Functions? + +Lambda durable functions enable resilient, long-running workflows with automatic state management. Key capabilities: + +- **Checkpoint/Replay**: Each `context.invoke()` creates a checkpoint. If the function fails, it replays from the beginning but skips completed steps using stored results. +- **Fault Tolerance**: Workflows automatically recover from failures without re-executing completed work. +- **Up to 1 Year Execution**: Durable functions can run for extended periods with waits that don't incur compute charges. + +### Data Flow + +``` +Input: {"id": "test-123", "name": "demo", "value": 5} + +Step 1 (Add): value = 5 + 10 = 15 +Step 2 (Transform): value = 15 × 2 = 30, name = "DEMO" +Step 3 (Finalize): value = 30 + 5 = 35, status = "COMPLETED" + +Output: {"value": 35, "final_value": 40, "transformed_name": "DEMO", "status": "COMPLETED"} +``` + +### Fault Tolerance Example + +If the orchestrator fails after Step 2 completes: +1. Lambda automatically retries the orchestrator +2. During replay, Steps 1 and 2 are **skipped** (results loaded from checkpoints) +3. Step 3 executes normally +4. Workflow completes successfully + +## Testing + +1. Get the orchestrator alias ARN from stack outputs: + ```bash + DURABLE_FUNCTION_ARN=$(aws cloudformation describe-stacks \ + --stack-name durable-function-chaining \ + --query 'Stacks[0].Outputs[?OutputKey==`OrchestratorAliasArn`].OutputValue' \ + --output text) + ``` + +2. Invoke the workflow: + ```bash + aws lambda invoke \ + --function-name "arn:aws:lambda:us-east-1:945972242554:function:durable-orchestrator:live" \ + --payload '{"id": "test-123", "name": "demo", "value": 5}' \ + --cli-binary-format raw-in-base64-out \ + response.json + + cat response.json + ``` + +3. Expected output: + ```json + { + "workflow": "completed", + "input": {"id": "test-123", "name": "demo", "value": 5}, + "output": { + "id": "test-123", + "name": "demo", + "step1_completed": true, + "value": 35, + "step2_completed": true, + "transformed_name": "DEMO", + "step3_completed": true, + "status": "COMPLETED", + "final_value": 40 + } + } + ``` + +## Cleanup + +```bash +sam delete --stack-name durable-function-chaining +``` + +## Resources + +- [Lambda durable functions Documentation](https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html) +- [Durable Execution SDK for Python](https://github.com/aws/aws-durable-execution-sdk-python) +- [AWS Blog: Build multi-step applications with Lambda durable functions](https://aws.amazon.com/blogs/aws/build-multi-step-applications-and-ai-workflows-with-aws-lambda-durable-functions/) + +---- +Copyright 2026 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +SPDX-License-Identifier: MIT-0 diff --git a/lambda-durable-function-chaining-sam/example-pattern.json b/lambda-durable-function-chaining-sam/example-pattern.json new file mode 100644 index 000000000..75df2744f --- /dev/null +++ b/lambda-durable-function-chaining-sam/example-pattern.json @@ -0,0 +1,78 @@ +{ + "title": "Function Chaining with AWS Lambda Durable Functions", + "description": "Demonstrates the function chaining pattern using Lambda durable functions with automatic checkpointing and fault-tolerant sequential execution", + "language": "Python", + "level": "200", + "framework": "SAM", + "introBox": { + "headline": "How it works", + "text": [ + "This pattern demonstrates the function chaining pattern using Lambda durable functions.", + "A durable orchestrator function chains three Lambda functions sequentially using context.invoke().", + "Each invocation creates an automatic checkpoint, enabling the workflow to resume from the last successful step after failures.", + "Step 1 (Add) initializes data and adds 10 to the input value.", + "Step 2 (Transform) doubles the value and transforms the name to uppercase.", + "Step 3 (Finalize) adds 5 to the value and sets the completion status.", + "The pattern showcases fault-tolerant workflow orchestration without managing state infrastructure." + ] + }, + "gitHub": { + "template": { + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/lambda-durable-function-chaining-sam", + "templateURL": "serverless-patterns/lambda-durable-function-chaining-sam", + "projectFolder": "lambda-durable-function-chaining-sam", + "templateFile": "template.yaml" + } + }, + "resources": { + "bullets": [ + { + "text": "Lambda durable functions Documentation", + "link": "https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html" + }, + { + "text": "Durable Execution SDK for Python", + "link": "https://github.com/aws/aws-durable-execution-sdk-python" + }, + { + "text": "AWS Blog: Build multi-step applications with Lambda durable functions", + "link": "https://aws.amazon.com/blogs/aws/build-multi-step-applications-and-ai-workflows-with-aws-lambda-durable-functions/" + } + ] + }, + "deploy": { + "text": [ + "sam build", + "sam deploy --guided" + ] + }, + "testing": { + "text": [ + "Get the orchestrator alias ARN from stack outputs:", + "DURABLE_FUNCTION_ARN=$(aws cloudformation describe-stacks --stack-name durable-function-chaining --query 'Stacks[0].Outputs[?OutputKey==`OrchestratorAliasArn`].OutputValue' --output text)", + "Invoke the workflow:", + "aws lambda invoke --function-name \"$DURABLE_FUNCTION_ARN\" --payload '{\"id\": \"test-123\", \"name\": \"demo\", \"value\": 5}' --cli-binary-format raw-in-base64-out response.json", + "cat response.json", + "Expected output shows value transformation: 5 → +10 (step1) → ×2 (step2) → +5 (step3) = 35" + ] + }, + "cleanup": { + "text": [ + "Delete the stack: `sam delete`" + ] + }, + "authors": [ + { + "name": "Sahil Bhimjiani", + "image": "https://drive.google.com/file/d/1E2p7S5UtU36x6Sk1xPS3XnSGJyIUoqK7/view?usp=drivesdk", + "bio": "Sahil Bhimjiani is a Solutions Architect at Amazon Web Services.", + "linkedin": "https://www.linkedin.com/in/sahil9701/" + }, + { + "name": "Anup Rajpara", + "image": "https://drive.google.com/file/d/1MqpPNLCqbU4kvvtTspNXZBqD99aVIJI9/view?usp=sharing", + "bio": "Anup is a Sr. Technical Account Manager at Amazon Web Services. He is passionate about serverless & event-driven architectures.", + "linkedin": "anup-rajpara-developer/" + } + ] +} diff --git a/lambda-durable-function-chaining-sam/src/orchestrator/app.py b/lambda-durable-function-chaining-sam/src/orchestrator/app.py new file mode 100644 index 000000000..c36da09c6 --- /dev/null +++ b/lambda-durable-function-chaining-sam/src/orchestrator/app.py @@ -0,0 +1,25 @@ +import os +from aws_durable_execution_sdk_python import DurableContext, durable_execution + + +@durable_execution +def lambda_handler(event, context: DurableContext): + """Durable orchestrator that chains 3 Lambda functions.""" + step1_arn = os.environ['STEP1_FUNCTION_ARN'] + step2_arn = os.environ['STEP2_FUNCTION_ARN'] + step3_arn = os.environ['STEP3_FUNCTION_ARN'] + + # Step 1: Add initial data + result1 = context.invoke(step1_arn, event, name='step1-add') + + # Step 2: Transform data + result2 = context.invoke(step2_arn, result1, name='step2-transform') + + # Step 3: Finalize + result3 = context.invoke(step3_arn, result2, name='step3-finalize') + + return { + 'workflow': 'completed', + 'input': event, + 'output': result3 + } diff --git a/lambda-durable-function-chaining-sam/src/orchestrator/requirements.txt b/lambda-durable-function-chaining-sam/src/orchestrator/requirements.txt new file mode 100644 index 000000000..85d9afabd --- /dev/null +++ b/lambda-durable-function-chaining-sam/src/orchestrator/requirements.txt @@ -0,0 +1 @@ +aws-durable-execution-sdk-python diff --git a/lambda-durable-function-chaining-sam/src/step1_add/app.py b/lambda-durable-function-chaining-sam/src/step1_add/app.py new file mode 100644 index 000000000..bcf050088 --- /dev/null +++ b/lambda-durable-function-chaining-sam/src/step1_add/app.py @@ -0,0 +1,8 @@ +def lambda_handler(event, context): + """Step 1: Add initial data fields to the input.""" + return { + 'id': event.get('id', 'unknown'), + 'name': event.get('name', 'default'), + 'step1_completed': True, + 'value': event.get('value', 0) + 10 + } diff --git a/lambda-durable-function-chaining-sam/src/step2_transform/app.py b/lambda-durable-function-chaining-sam/src/step2_transform/app.py new file mode 100644 index 000000000..f57e18dee --- /dev/null +++ b/lambda-durable-function-chaining-sam/src/step2_transform/app.py @@ -0,0 +1,8 @@ +def lambda_handler(event, context): + """Step 2: Transform and enrich the data.""" + return { + **event, + 'step2_completed': True, + 'value': event.get('value', 0) * 2, + 'transformed_name': event.get('name', '').upper() + } diff --git a/lambda-durable-function-chaining-sam/src/step3_finalize/app.py b/lambda-durable-function-chaining-sam/src/step3_finalize/app.py new file mode 100644 index 000000000..593ec400f --- /dev/null +++ b/lambda-durable-function-chaining-sam/src/step3_finalize/app.py @@ -0,0 +1,8 @@ +def lambda_handler(event, context): + """Step 3: Finalize the data with status.""" + return { + **event, + 'step3_completed': True, + 'status': 'COMPLETED', + 'final_value': event.get('value', 0) + 5 + } diff --git a/lambda-durable-function-chaining-sam/template.yaml b/lambda-durable-function-chaining-sam/template.yaml new file mode 100644 index 000000000..9fc70cfbf --- /dev/null +++ b/lambda-durable-function-chaining-sam/template.yaml @@ -0,0 +1,74 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: Function Chaining with AWS Lambda Durable Functions + +Globals: + Function: + Timeout: 30 + Runtime: python3.14 + MemorySize: 512 + +Resources: + # Worker Functions + Step1AddFunction: + Type: AWS::Serverless::Function + Properties: + FunctionName: step1-add + CodeUri: src/step1_add/ + Handler: app.lambda_handler + + Step2TransformFunction: + Type: AWS::Serverless::Function + Properties: + FunctionName: step2-transform + CodeUri: src/step2_transform/ + Handler: app.lambda_handler + + Step3FinalizeFunction: + Type: AWS::Serverless::Function + Properties: + FunctionName: step3-finalize + CodeUri: src/step3_finalize/ + Handler: app.lambda_handler + + # Durable Orchestrator Function + OrchestratorFunction: + Type: AWS::Serverless::Function + Properties: + FunctionName: durable-orchestrator + CodeUri: src/orchestrator/ + Handler: app.lambda_handler + Timeout: 900 + AutoPublishAlias: live + DurableConfig: + ExecutionTimeout: 900 + RetentionPeriodInDays: 7 + Environment: + Variables: + STEP1_FUNCTION_ARN: !Sub ${Step1AddFunction.Arn}:$LATEST + STEP2_FUNCTION_ARN: !Sub ${Step2TransformFunction.Arn}:$LATEST + STEP3_FUNCTION_ARN: !Sub ${Step3FinalizeFunction.Arn}:$LATEST + Policies: + - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicDurableExecutionRolePolicy + - Version: '2012-10-17' + Statement: + - Effect: Allow + Action: lambda:InvokeFunction + Resource: + - !Sub ${Step1AddFunction.Arn}:* + - !Sub ${Step2TransformFunction.Arn}:* + - !Sub ${Step3FinalizeFunction.Arn}:* + - !GetAtt Step1AddFunction.Arn + - !GetAtt Step2TransformFunction.Arn + - !GetAtt Step3FinalizeFunction.Arn + +Outputs: + OrchestratorAliasArn: + Description: Orchestrator function Alias ARN (use this for invocations) + Value: !Ref OrchestratorFunction.Alias + Step1FunctionArn: + Value: !GetAtt Step1AddFunction.Arn + Step2FunctionArn: + Value: !GetAtt Step2TransformFunction.Arn + Step3FunctionArn: + Value: !GetAtt Step3FinalizeFunction.Arn From 9fe29ba5e3d0a0ff4dce3c13820d8805cf2187d2 Mon Sep 17 00:00:00 2001 From: sahil bhimjiani Date: Fri, 6 Feb 2026 16:24:44 -0600 Subject: [PATCH 2/4] updating README --- lambda-durable-function-chaining-sam/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lambda-durable-function-chaining-sam/README.md b/lambda-durable-function-chaining-sam/README.md index 9b3960489..f5f1b2433 100644 --- a/lambda-durable-function-chaining-sam/README.md +++ b/lambda-durable-function-chaining-sam/README.md @@ -105,7 +105,7 @@ If the orchestrator fails after Step 2 completes: 2. Invoke the workflow: ```bash aws lambda invoke \ - --function-name "arn:aws:lambda:us-east-1:945972242554:function:durable-orchestrator:live" \ + --function-name "$DURABLE_FUNCTION_ARN" \ --payload '{"id": "test-123", "name": "demo", "value": 5}' \ --cli-binary-format raw-in-base64-out \ response.json From 103e0845f5ab906ffc28825945469a3925e4338c Mon Sep 17 00:00:00 2001 From: sbbhimji <86671986+sbbhimji@users.noreply.github.com> Date: Sun, 8 Feb 2026 13:38:05 -0600 Subject: [PATCH 3/4] Apply suggestions from code review Co-authored-by: Ben <9841563+bfreiberg@users.noreply.github.com> --- lambda-durable-function-chaining-sam/README.md | 6 +++--- lambda-durable-function-chaining-sam/example-pattern.json | 6 +++--- lambda-durable-function-chaining-sam/template.yaml | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lambda-durable-function-chaining-sam/README.md b/lambda-durable-function-chaining-sam/README.md index f5f1b2433..cb20173f6 100644 --- a/lambda-durable-function-chaining-sam/README.md +++ b/lambda-durable-function-chaining-sam/README.md @@ -1,4 +1,4 @@ -# Function Chaining with AWS Lambda Durable Functions +# Function chaining with AWS Lambda durable functions This pattern demonstrates the **function chaining** workflow pattern using AWS Lambda durable functions. A durable orchestrator chains three Lambda functions sequentially, with automatic checkpointing after each step for fault tolerance. @@ -64,9 +64,9 @@ flowchart LR The orchestrator uses `context.invoke()` to chain 3 Lambda functions with automatic checkpointing. -### What are Lambda Durable Functions? +### What are AWS Lambda durable functions? -Lambda durable functions enable resilient, long-running workflows with automatic state management. Key capabilities: +Lambda durable functions enable you to build resilient, long-running workflows with automatic state management. Key capabilities: - **Checkpoint/Replay**: Each `context.invoke()` creates a checkpoint. If the function fails, it replays from the beginning but skips completed steps using stored results. - **Fault Tolerance**: Workflows automatically recover from failures without re-executing completed work. diff --git a/lambda-durable-function-chaining-sam/example-pattern.json b/lambda-durable-function-chaining-sam/example-pattern.json index 75df2744f..a632c5071 100644 --- a/lambda-durable-function-chaining-sam/example-pattern.json +++ b/lambda-durable-function-chaining-sam/example-pattern.json @@ -1,5 +1,5 @@ { - "title": "Function Chaining with AWS Lambda Durable Functions", + "title": "Function chaining with AWS Lambda durable functions", "description": "Demonstrates the function chaining pattern using Lambda durable functions with automatic checkpointing and fault-tolerant sequential execution", "language": "Python", "level": "200", @@ -58,7 +58,7 @@ }, "cleanup": { "text": [ - "Delete the stack: `sam delete`" + "Delete the stack: sam delete" ] }, "authors": [ @@ -66,7 +66,7 @@ "name": "Sahil Bhimjiani", "image": "https://drive.google.com/file/d/1E2p7S5UtU36x6Sk1xPS3XnSGJyIUoqK7/view?usp=drivesdk", "bio": "Sahil Bhimjiani is a Solutions Architect at Amazon Web Services.", - "linkedin": "https://www.linkedin.com/in/sahil9701/" + "linkedin": "sahil9701" }, { "name": "Anup Rajpara", diff --git a/lambda-durable-function-chaining-sam/template.yaml b/lambda-durable-function-chaining-sam/template.yaml index 9fc70cfbf..882a1a361 100644 --- a/lambda-durable-function-chaining-sam/template.yaml +++ b/lambda-durable-function-chaining-sam/template.yaml @@ -1,6 +1,6 @@ AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 -Description: Function Chaining with AWS Lambda Durable Functions +Description: Function chaining with AWS Lambda durable functions Globals: Function: From 51c747b3d25e3c2d765f0873974864ec034361a4 Mon Sep 17 00:00:00 2001 From: sbbhimji <86671986+sbbhimji@users.noreply.github.com> Date: Tue, 10 Feb 2026 09:06:26 -0600 Subject: [PATCH 4/4] Apply suggestions from code review Co-authored-by: Ben <9841563+bfreiberg@users.noreply.github.com> --- lambda-durable-function-chaining-sam/README.md | 2 +- lambda-durable-function-chaining-sam/example-pattern.json | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lambda-durable-function-chaining-sam/README.md b/lambda-durable-function-chaining-sam/README.md index cb20173f6..2b0ecb932 100644 --- a/lambda-durable-function-chaining-sam/README.md +++ b/lambda-durable-function-chaining-sam/README.md @@ -51,7 +51,7 @@ flowchart LR E -->|checkpoint| B B --> F[Output] - subgraph Durable Function + subgraph Lambda durable function B end diff --git a/lambda-durable-function-chaining-sam/example-pattern.json b/lambda-durable-function-chaining-sam/example-pattern.json index a632c5071..fa1108948 100644 --- a/lambda-durable-function-chaining-sam/example-pattern.json +++ b/lambda-durable-function-chaining-sam/example-pattern.json @@ -3,7 +3,7 @@ "description": "Demonstrates the function chaining pattern using Lambda durable functions with automatic checkpointing and fault-tolerant sequential execution", "language": "Python", "level": "200", - "framework": "SAM", + "framework": "AWS SAM", "introBox": { "headline": "How it works", "text": [ @@ -49,10 +49,10 @@ "testing": { "text": [ "Get the orchestrator alias ARN from stack outputs:", - "DURABLE_FUNCTION_ARN=$(aws cloudformation describe-stacks --stack-name durable-function-chaining --query 'Stacks[0].Outputs[?OutputKey==`OrchestratorAliasArn`].OutputValue' --output text)", + "DURABLE_FUNCTION_ARN=$(aws cloudformation describe-stacks --stack-name durable-function-chaining --query 'Stacks[0].Outputs[?OutputKey==`OrchestratorAliasArn`].OutputValue' --output text)", "Invoke the workflow:", - "aws lambda invoke --function-name \"$DURABLE_FUNCTION_ARN\" --payload '{\"id\": \"test-123\", \"name\": \"demo\", \"value\": 5}' --cli-binary-format raw-in-base64-out response.json", - "cat response.json", + "aws lambda invoke --function-name \"$DURABLE_FUNCTION_ARN\" --payload '{\"id\": \"test-123\", \"name\": \"demo\", \"value\": 5}' --cli-binary-format raw-in-base64-out response.json", + "cat response.json", "Expected output shows value transformation: 5 → +10 (step1) → ×2 (step2) → +5 (step3) = 35" ] },