diff --git a/lambda-durable-invoke-lambda-sam-python/README.md b/lambda-durable-invoke-lambda-sam-python/README.md new file mode 100644 index 000000000..33d0ff9af --- /dev/null +++ b/lambda-durable-invoke-lambda-sam-python/README.md @@ -0,0 +1,89 @@ +# Lambda durable functions invoking AWS Lambda function (Python) + +This pattern demonstrates how an AWS Lambda durable function can invoke a standard AWS Lambda function using `context.invoke()` from the durable execution SDK. The invocation is automatically checkpointed, so if the durable function is interrupted after the invoked function completes, it resumes with the stored result without re-invoking the target function. + +Learn more about this pattern at Serverless Land Patterns: [https://serverlessland.com/patterns/lambda-durable-invoke-lambda-sam-python](https://serverlessland.com/patterns/lambda-durable-invoke-lambda-sam-python) + +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 Serverless Application Model](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-install.html) (AWS SAM) installed +* Python 3.14 + +## 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-invoke-lambda-sam-python + ``` +1. From the command line, use AWS SAM to build and deploy the AWS resources for the pattern as specified in the template.yaml file: + ``` + sam build + sam deploy --guided + ``` +1. During the prompts: + * Enter a stack name + * Enter the desired AWS Region (durable functions are available in supported regions) + * Allow SAM CLI to create IAM roles with the required permissions. + + Once you have run `sam deploy --guided` mode once and saved arguments to a configuration file (samconfig.toml), you can use `sam deploy` in future to use these defaults. + +1. Note the outputs from the SAM deployment process. These contain the resource names and/or ARNs which are used for testing. + +## How it works + +This pattern deploys two Lambda functions: + +1. **DurableLambdaFunction** - A durable Lambda function that orchestrates the workflow. It uses the `@durable_execution` decorator and performs two checkpointed operations: + - A `@durable_step` that prepares and validates input values. + - A `context.invoke()` call that invokes the ProcessorFunction and waits for its result. + +2. **ProcessorFunction** - A standard Lambda function that receives a list of numeric values and returns computed statistics (sum, average, max, min). + +The AWS Lambda durable function uses automatic checkpointing. Each step and invoke operation creates a checkpoint. If the function is interrupted (e.g., due to a transient failure), it replays from the beginning but skips completed checkpoints, resuming execution from where it left off. + + +## Testing + +1. After deployment, invoke the durable function using the alias ARN from the stack outputs: + + ```bash + aws lambda invoke \ + --function-name \ + --payload '{"values": [10, 20, 30, 40, 50]}' \ + --cli-binary-format raw-in-base64-out \ + output.json + ``` + +2. Check the response: + + ```bash + cat output.json + ``` + + Expected output: + ```json + {"statusCode": 200, "body": "{\"message\": \"Durable orchestration completed successfully\", \"input_values\": [10, 20, 30, 40, 50], \"processing_result\": {\"operation\": \"sum_and_average\", \"count\": 5, \"sum\": 150, \"average\": 30.0, \"max\": 50, \"min\": 10}}"} + ``` + +3. Monitor the durable execution steps in the Lambda console under the **Durable executions** tab of the DurableLambdaFunction. + +## Cleanup + +1. Delete the stack + ```bash + sam delete + ``` + +---- +Copyright 2026 Amazon.com, Inc. or its affiliates. All Rights Reserved. + +SPDX-License-Identifier: MIT-0 diff --git a/lambda-durable-invoke-lambda-sam-python/example-pattern.json b/lambda-durable-invoke-lambda-sam-python/example-pattern.json new file mode 100644 index 000000000..431cbc0dd --- /dev/null +++ b/lambda-durable-invoke-lambda-sam-python/example-pattern.json @@ -0,0 +1,63 @@ +{ + "title": "AWS Lambda durable function invoking an AWS Lambda Function", + "description": "Lambda durable function invokes a standard Lambda function using context.invoke() with automatic checkpointing.", + "language": "Python", + "level": "200", + "framework": "SAM", + "introBox": { + "headline": "How it works", + "text": [ + "This pattern deploys an AWS Lambda durable function and a standard AWS Lambda function. The durable function uses the durable execution SDK to orchestrate a workflow that prepares input data in a checkpointed step and then invokes the standard Lambda function using context.invoke().", + "The context.invoke() call creates a checkpoint so that if the durable function is interrupted after the invoked function completes, it resumes with the stored result without re-invoking the processor function.", + "This pattern deploys two Lambda functions with the required IAM permissions for durable execution and cross-function invocation." + ] + }, + "gitHub": { + "template": { + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/lambda-durable-invoke-lambda-sam-python", + "templateURL": "serverless-patterns/lambda-durable-invoke-lambda-sam-python", + "projectFolder": "lambda-durable-invoke-lambda-sam-python", + "templateFile": "template.yaml" + } + }, + "resources": { + "bullets": [ + { + "text": "AWS Lambda durable functions", + "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": "Chained invocations across functions", + "link": "https://docs.aws.amazon.com/lambda/latest/dg/durable-examples.html" + } + ] + }, + "deploy": { + "text": [ + "sam build", + "sam deploy --guided" + ] + }, + "testing": { + "text": [ + "See the GitHub repo for detailed testing instructions." + ] + }, + "cleanup": { + "text": [ + "Delete the stack: sam delete." + ] + }, + "authors": [ + { + "name": "Sidharth Kothari", + "image": "https://drive.google.com/file/d/1sUXFJLHYuCmadcu4Q7mhb0mBnWfTcrtT/view", + "bio": "Cloud Engineer II at AWS with expertise in serverless, GenAI, event-driven and microservice-based applications", + "linkedin": "sidharthkothari" + } + ] +} diff --git a/lambda-durable-invoke-lambda-sam-python/lambda-durable-invoke-lambda-sam-python.json b/lambda-durable-invoke-lambda-sam-python/lambda-durable-invoke-lambda-sam-python.json new file mode 100644 index 000000000..9a00b0503 --- /dev/null +++ b/lambda-durable-invoke-lambda-sam-python/lambda-durable-invoke-lambda-sam-python.json @@ -0,0 +1,92 @@ +{ + "title": "AWS Lambda durable function invoking an AWS Lambda Function", + "description": "Lambda durable function invokes a standard Lambda function using context.invoke() with automatic checkpointing.", + "language": "Python", + "level": "200", + "framework": "AWS SAM", + "introBox": { + "headline": "How it works", + "text": [ + "This pattern deploys an AWS Lambda durable function and a standard AWS Lambda function. The durable function uses the durable execution SDK to orchestrate a workflow that prepares input data in a checkpointed step and then invokes the standard Lambda function using context.invoke().", + "The context.invoke() call creates a checkpoint so that if the durable function is interrupted after the invoked function completes, it resumes with the stored result without re-invoking the processor function.", + "This pattern deploys two Lambda functions with the required IAM permissions for durable execution and cross-function invocation." + ] + }, + "gitHub": { + "template": { + "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/lambda-durable-invoke-lambda-sam-python", + "templateURL": "serverless-patterns/lambda-durable-invoke-lambda-sam-python", + "projectFolder": "lambda-durable-invoke-lambda-sam-python", + "templateFile": "template.yaml" + } + }, + "services": { + "from": { + "serviceName": "AWS Lambda", + "serviceURL": "/lambda/" + }, + "to": { + "serviceName": "AWS Lambda", + "serviceURL": "/lambda/" + } + }, + "patternArch": { + "icon1": { + "x": 20, + "y": 50, + "service": "lambda", + "label": "Lambda durable function" + }, + "icon2": { + "x": 80, + "y": 50, + "service": "lambda", + "label": "Lambda function" + }, + "line1": { + "from": "icon1", + "to": "icon2" + } + }, + "resources": { + "bullets": [ + { + "text": "AWS Lambda durable functions", + "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": "Chained invocations across functions", + "link": "https://docs.aws.amazon.com/lambda/latest/dg/durable-examples.html" + } + ] + }, + "deploy": { + "text": [ + "sam build", + "sam deploy --guided" + ] + }, + "testing": { + "text": [ + "See the GitHub repo for detailed testing instructions." + ] + }, + "cleanup": { + "text": [ + "Delete the stack: sam delete." + ] + }, + "authors": [ + { + "name": "Sidharth Kothari", + "image": "https://drive.google.com/file/d/1sUXFJLHYuCmadcu4Q7mhb0mBnWfTcrtT/view", + "bio": "Cloud Engineer II at AWS with expertise in serverless, GenAI, event-driven and microservice-based applications", + "linkedin": "sidharthkothari" + } + ], + "patternType": "Serverless" +} diff --git a/lambda-durable-invoke-lambda-sam-python/src/durable_lambda_function.py b/lambda-durable-invoke-lambda-sam-python/src/durable_lambda_function.py new file mode 100644 index 000000000..2c2832e4c --- /dev/null +++ b/lambda-durable-invoke-lambda-sam-python/src/durable_lambda_function.py @@ -0,0 +1,50 @@ +import json +import os +from aws_durable_execution_sdk_python import ( + DurableContext, + StepContext, + durable_execution, + durable_step, +) + +PROCESSOR_FUNCTION_NAME = os.environ["PROCESSOR_FUNCTION_NAME"] + + +@durable_step +def prepare_input(step_ctx: StepContext, raw_values: list) -> dict: + """Prepare and validate input values before invoking the processor function.""" + step_ctx.logger.info("Preparing input values for processing") + return { + "values": raw_values, + "operation": "sum_and_average", + } + + +@durable_execution +def lambda_handler(event: dict, context: DurableContext) -> dict: + """Durable function that orchestrates processing by invoking another Lambda.""" + raw_values = event.get("values", [10, 20, 30, 40, 50]) + context.logger.info("Starting durable orchestration", extra={"values": raw_values}) + + # Step 1: Prepare the input (checkpointed) + prepared = context.step(prepare_input(raw_values), name="prepare_input") + + # Step 2: Invoke the processor Lambda function (checkpointed) + # If the durable function is interrupted after this completes, + # it resumes with the stored result without re-invoking the processor. + result = context.invoke( + function_name=PROCESSOR_FUNCTION_NAME, + payload=prepared, + name="invoke_processor", + ) + + context.logger.info("Processing complete", extra={"result": result}) + + return { + "statusCode": 200, + "body": json.dumps({ + "message": "Durable orchestration completed successfully", + "input_values": raw_values, + "processing_result": result, + }), + } diff --git a/lambda-durable-invoke-lambda-sam-python/src/processor_function.py b/lambda-durable-invoke-lambda-sam-python/src/processor_function.py new file mode 100644 index 000000000..b35d0ee6c --- /dev/null +++ b/lambda-durable-invoke-lambda-sam-python/src/processor_function.py @@ -0,0 +1,21 @@ +def lambda_handler(event, context): + """Standard Lambda function that processes sample values.""" + values = event.get("values", []) + operation = event.get("operation", "sum_and_average") + + if not values: + return {"error": "No values provided"} + + total = sum(values) + average = total / len(values) + maximum = max(values) + minimum = min(values) + + return { + "operation": operation, + "count": len(values), + "sum": total, + "average": average, + "max": maximum, + "min": minimum, + } diff --git a/lambda-durable-invoke-lambda-sam-python/src/requirements.txt b/lambda-durable-invoke-lambda-sam-python/src/requirements.txt new file mode 100644 index 000000000..7b359a340 --- /dev/null +++ b/lambda-durable-invoke-lambda-sam-python/src/requirements.txt @@ -0,0 +1 @@ +aws-durable-execution-sdk-python==1.3.0 diff --git a/lambda-durable-invoke-lambda-sam-python/template.yaml b/lambda-durable-invoke-lambda-sam-python/template.yaml new file mode 100644 index 000000000..9a4e35cfa --- /dev/null +++ b/lambda-durable-invoke-lambda-sam-python/template.yaml @@ -0,0 +1,51 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: > + Serverless pattern - Lambda durable function invoking another AWS Lambda function (Python). + Demonstrates how a Lambda durable function can use context.invoke() to call a standard + Lambda function as a checkpointed step in its workflow. + +Globals: + Function: + Timeout: 30 + MemorySize: 128 + +Resources: + # Standard AWS Lambda function that processes sample values + ProcessorFunction: + Type: AWS::Serverless::Function + Properties: + Handler: processor_function.lambda_handler + Runtime: python3.14 + CodeUri: src/ + + # Lambda durable function that orchestrates the workflow + DurableLambdaFunction: + Type: AWS::Serverless::Function + Properties: + Handler: durable_lambda_function.lambda_handler + Runtime: python3.14 + CodeUri: src/ + Timeout: 600 + DurableConfig: + ExecutionTimeout: 600 + RetentionPeriodInDays: 7 + AutoPublishAlias: live + Environment: + Variables: + PROCESSOR_FUNCTION_NAME: !Ref ProcessorFunction + Policies: + - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicDurableExecutionRolePolicy + - LambdaInvokePolicy: + FunctionName: !Ref ProcessorFunction + +Outputs: + DurableLambdaFunctionArn: + Description: ARN of Lambda durable function + Value: !GetAtt DurableLambdaFunction.Arn + DurableLambdaFunctionAliasArn: + Description: Alias ARN of the Lambda durable function (use this for invocations) + Value: !Ref DurableLambdaFunction.Alias + ProcessorFunctionArn: + Description: ARN of the processor Lambda function + Value: !GetAtt ProcessorFunction.Arn