diff --git a/lambda-durable-order-processing-sam/.gitignore b/lambda-durable-order-processing-sam/.gitignore
new file mode 100644
index 000000000..38d4d358f
--- /dev/null
+++ b/lambda-durable-order-processing-sam/.gitignore
@@ -0,0 +1,16 @@
+# SAM Build Artifacts
+.aws-sam/
+samconfig.toml
+*.zip
+
+# Node
+node_modules/
+*.log
+
+# Temporary Files
+checkpoint-policy.json
+DEPLOYMENT.md
+
+# OS
+.DS_Store
+Thumbs.db
diff --git a/lambda-durable-order-processing-sam/README.md b/lambda-durable-order-processing-sam/README.md
new file mode 100644
index 000000000..038ce1d22
--- /dev/null
+++ b/lambda-durable-order-processing-sam/README.md
@@ -0,0 +1,494 @@
+# Order Processing Workflow with AWS Lambda Durable Functions
+
+This pattern demonstrates a multi-step order processing workflow using AWS Lambda Durable Functions. The workflow handles order validation, payment processing, inventory checking, and shipping arrangement with automatic checkpointing and state persistence across long-running operations.
+
+**Important:** Lambda Durable Functions are currently available in the **us-east-2 (Ohio)** region only.
+
+## Architecture
+
+
+
+The solution uses a dual-function architecture:
+- **Durable Function**: Handles async order processing with 17 steps and automatic checkpointing
+- **Status Function**: Provides real-time order status via synchronous API calls
+
+### Order Processing Workflow (17 Steps)
+
+The workflow consists of 17 steps organized into 5 phases:
+
+**Phase 1: Validation (Steps 1-3)**
+1. Validate Order - Check order data and customer information
+2. Check Inventory - Verify item availability
+3. Process Payment - Process payment transaction
+
+**Phase 2: Risk Assessment (Steps 4-6)**
+4. Reserve Inventory - Lock inventory for order
+5. Fraud Check - Run fraud detection
+6. Credit Check - Verify credit (for orders > $1000)
+
+**Phase 3: Invoice (Step 7)**
+7. Generate Invoice - Create customer invoice
+
+**Phase 4: Fulfillment (Steps 8-12)**
+- *Wait 5 minutes for warehouse processing (no compute cost)*
+8. Pick Items - Warehouse picks items
+9. Quality Check - Inspect items
+10. Package Order - Package for shipping
+11. Generate Shipping Label - Create shipping label
+
+**Phase 5: Shipping & Completion (Steps 13-17)**
+- *Wait 3 minutes for carrier pickup (no compute cost)*
+12. Ship Order - Hand off to carrier
+13. Send Notifications - Email/SMS to customer
+14. Update Loyalty Points - Award loyalty points
+15. Complete Order - Mark order as complete
+
+Each step is automatically checkpointed, allowing the workflow to resume from the last successful step if interrupted.
+
+## Key Features
+
+- ✅ **Automatic Checkpointing** - Each step is checkpointed automatically
+- ✅ **Failure Recovery** - Resumes from last checkpoint on failure
+- ✅ **Compensation Logic** - Rolls back on errors
+- ✅ **Wait States** - Efficient waiting without compute charges
+- ✅ **State Persistence** - Order status stored in DynamoDB
+- ✅ **API Integration** - REST API for order submission and status checking
+
+## 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 18+](https://nodejs.org/) installed
+
+### Required IAM Permissions
+
+Your AWS CLI user/role needs the following permissions for deployment and testing:
+- **CloudFormation**: `cloudformation:DescribeStacks`, `cloudformation:DeleteStack`
+- **Lambda**: `lambda:CreateFunction`, `lambda:InvokeFunction`, `lambda:GetFunction`
+- **DynamoDB**: `dynamodb:Scan`, `dynamodb:GetItem`
+- **CloudWatch Logs**: `logs:DescribeLogGroups`, `logs:FilterLogEvents`, `logs:GetLogEvents`, `logs:TailLogEvents`
+- **API Gateway**: `apigateway:GET`
+- **IAM**: `iam:CreateRole`, `iam:AttachRolePolicy`, `iam:PassRole`
+
+
+## Deployment
+
+1. Navigate to the pattern directory:
+ ```bash
+ cd lambda-durable-order-processing-sam
+ ```
+
+2. Install dependencies:
+ ```bash
+ cd src && npm install && cd ..
+ ```
+
+3. Build the SAM application:
+ ```bash
+ sam build
+ ```
+
+4. Deploy the application (must use us-east-2 region):
+ ```bash
+ sam deploy --guided --region us-east-2
+ ```
+
+ During the guided deployment:
+ - Stack Name: `lambda-durable-order-processing`
+ - AWS Region: `us-east-2`
+ - Confirm changes: `N`
+ - Allow SAM CLI IAM role creation: `Y`
+ - Disable rollback: `N`
+ - Save arguments to config file: `Y`
+
+5. Note the `OrderApiEndpoint` from the outputs.
+
+## Testing
+
+### Step 1: Get Your API Endpoint
+
+Retrieve your API endpoint from the CloudFormation stack:
+
+```bash
+API_ENDPOINT=$(aws cloudformation describe-stacks \
+ --stack-name lambda-durable-order-processing \
+ --region us-east-2 \
+ --query 'Stacks[0].Outputs[?OutputKey==`OrderApiEndpoint`].OutputValue' \
+ --output text)
+
+echo "API Endpoint: $API_ENDPOINT"
+```
+
+### Step 2: Create Test Orders
+
+**Test 1: Low-value order (< $1000)**
+```bash
+curl -X POST ${API_ENDPOINT}/orders \
+ -H "Content-Type: application/json" \
+ -d '{
+ "customerId": "CUST-001",
+ "customerEmail": "customer1@example.com",
+ "items": [
+ {"productId": "BOOK-001", "name": "Programming Book", "quantity": 2, "price": 45.99}
+ ]
+ }'
+```
+
+Expected response:
+```json
+{
+ "message": "Order processing initiated",
+ "orderId": "order-1764821208592"
+}
+```
+
+**Test 2: High-value order (> $1000, triggers credit check)**
+```bash
+curl -X POST ${API_ENDPOINT}/orders \
+ -H "Content-Type: application/json" \
+ -d '{
+ "customerId": "CUST-002",
+ "customerEmail": "customer2@example.com",
+ "items": [
+ {"productId": "SERVER-001", "name": "Enterprise Server", "quantity": 1, "price": 3500.00}
+ ]
+ }'
+```
+
+**Test 3: Multiple items order**
+```bash
+curl -X POST ${API_ENDPOINT}/orders \
+ -H "Content-Type: application/json" \
+ -d '{
+ "customerId": "CUST-003",
+ "customerEmail": "customer3@example.com",
+ "items": [
+ {"productId": "LAPTOP-001", "name": "Gaming Laptop", "quantity": 1, "price": 1299.99},
+ {"productId": "MOUSE-001", "name": "Wireless Mouse", "quantity": 2, "price": 29.99},
+ {"productId": "KEYBOARD-001", "name": "Mechanical Keyboard", "quantity": 1, "price": 149.99}
+ ]
+ }'
+```
+
+**Test 4: Edge case - Empty items (should fail validation)**
+```bash
+curl -X POST ${API_ENDPOINT}/orders \
+ -H "Content-Type: application/json" \
+ -d '{
+ "customerId": "CUST-004",
+ "customerEmail": "customer4@example.com",
+ "items": []
+ }'
+```
+
+### Step 3: Check Order Status
+
+Wait 10 seconds, then check the order status using the order ID from the response:
+
+```bash
+ORDER_ID="order-1764821208592" # Replace with your order ID
+curl ${API_ENDPOINT}/orders/${ORDER_ID} | jq '.'
+```
+
+Expected response:
+```json
+{
+ "orderId": "order-1764821208592",
+ "status": "awaiting-warehouse",
+ "customerId": "CUST-001",
+ "customerEmail": "customer1@example.com",
+ "total": 91.98,
+ "items": [
+ {
+ "name": "Programming Book",
+ "quantity": 2,
+ "productId": "BOOK-001",
+ "price": 45.99
+ }
+ ],
+ "createdAt": "2025-12-04T04:06:48.964Z",
+ "lastUpdated": "2025-12-04T04:06:50.621Z"
+}
+```
+
+### Step 4: Track Status Progression
+
+Poll the order status to see it progress through the workflow:
+
+```bash
+# Check status every 30 seconds
+for i in {1..10}; do
+ echo "=== Check $i at $(date +%H:%M:%S) ==="
+ curl -s ${API_ENDPOINT}/orders/${ORDER_ID} | jq '{status, lastUpdated}'
+ sleep 30
+done
+```
+
+You'll see the status progress through:
+- `validated` → `inventory-checked` → `payment-processed` → `inventory-reserved` → `fraud-checked` → `invoice-generated` → `awaiting-warehouse` (5 min wait) → `items-picked` → `quality-checked` → `packaged` → `awaiting-pickup` (3 min wait) → `shipped` → `completed`
+
+### Step 5: Monitor Lambda Logs
+
+View real-time Lambda execution logs:
+
+```bash
+# Get function name
+FUNCTION_NAME=$(aws cloudformation describe-stack-resources \
+ --stack-name lambda-durable-order-processing \
+ --region us-east-2 \
+ --query 'StackResources[?LogicalResourceId==`OrderProcessingFunction`].PhysicalResourceId' \
+ --output text)
+
+# Tail logs
+aws logs tail /aws/lambda/${FUNCTION_NAME} \
+ --follow \
+ --format short \
+ --region us-east-2
+```
+
+Look for checkpoint and step execution messages:
+```
+Starting order processing { orderId: 'order-1764821208592' }
+Validating order { orderId: 'order-1764821208592' }
+Checking inventory { orderId: 'order-1764821208592' }
+Processing payment { orderId: 'order-1764821208592', amount: 91.98 }
+Waiting for warehouse processing { orderId: 'order-1764821208592' }
+```
+
+### Step 6: Verify Amazon DynamoDB Storage
+
+Check orders stored in DynamoDB:
+
+```bash
+TABLE_NAME=$(aws cloudformation describe-stacks \
+ --stack-name lambda-durable-order-processing \
+ --region us-east-2 \
+ --query 'Stacks[0].Outputs[?OutputKey==`OrdersTableName`].OutputValue' \
+ --output text)
+
+# Scan all orders
+aws dynamodb scan \
+ --table-name ${TABLE_NAME} \
+ --region us-east-2 \
+ --max-items 5 | jq '.Items[] | {orderId: .orderId.S, status: .status.S, total: .total.N}'
+```
+
+### Step 7: Test Concurrent Orders
+
+Create multiple orders simultaneously to test concurrency:
+
+```bash
+for i in {1..5}; do
+ curl -X POST ${API_ENDPOINT}/orders \
+ -H "Content-Type: application/json" \
+ -d "{
+ \"customerId\": \"CONCURRENT-$i\",
+ \"customerEmail\": \"concurrent$i@example.com\",
+ \"items\": [{\"productId\": \"PROD-$i\", \"name\": \"Product $i\", \"quantity\": 1, \"price\": $((100 + i * 10))}]
+ }" &
+done
+wait
+echo "All 5 orders submitted concurrently"
+```
+
+### Expected Test Results
+
+- ✅ **Low-value orders**: Complete all 17 steps (no credit check)
+- ✅ **High-value orders**: Include credit check step (Step 6)
+- ✅ **Multi-item orders**: Calculate total correctly
+- ✅ **Invalid orders**: Fail validation and mark as failed
+- ✅ **Status API**: Returns real-time order status
+- ✅ **Concurrent orders**: All process independently
+- ✅ **Wait periods**: 8 minutes total (5 min + 3 min) with no compute cost
+
+
+
+## How It Works
+
+### Durable Execution
+
+The order processing function uses the `@aws/durable-execution-sdk-js` to create checkpoints at each step:
+
+```javascript
+import { withDurableExecution } from '@aws/durable-execution-sdk-js';
+
+export const handler = withDurableExecution(async (event, context) => {
+ // Each step is automatically checkpointed
+ await context.step('validate-order', async () => {
+ console.log('Validating order');
+ // Validation logic
+ });
+
+ // Wait 5 seconds (simulating external API call)
+ await context.wait({ seconds: 5 });
+
+ await context.step('process-payment', async () => {
+ console.log('Processing payment');
+ // Payment logic
+ });
+
+ // More steps...
+});
+```
+
+### Checkpoint Behavior
+
+When a durable function executes:
+1. Each `context.step()` creates a checkpoint before execution
+2. If the function is interrupted, Lambda saves the checkpoint state
+3. On retry, the function replays from the beginning
+4. Completed steps are skipped using stored checkpoint results
+5. Execution continues from the last incomplete step
+
+You'll see the same order ID appear multiple times in logs - this is the durable execution resuming from checkpoints!
+
+### State Persistence
+
+Final order state is saved to DynamoDB after all steps complete:
+
+```javascript
+await context.step('save-order', async () => {
+ await dynamodb.putItem({
+ TableName: process.env.ORDERS_TABLE,
+ Item: { orderId, status: 'completed', ... }
+ });
+});
+```
+
+## Configuration
+
+### Durable Execution Settings
+
+The durable function must be created with durable configuration (cannot be added to existing functions):
+
+```bash
+aws lambda create-function \
+ --function-name my-durable-function \
+ --runtime nodejs22.x \
+ --durable-config '{"ExecutionTimeout":86400,"RetentionPeriodInDays":7}' \
+ ...
+```
+
+- **ExecutionTimeout**: 86400 seconds (24 hours)
+- **RetentionPeriodInDays**: 7 days
+
+### IAM Permissions
+
+The function requires these permissions:
+
+```yaml
+Policies:
+ - Statement:
+ - Effect: Allow
+ Action:
+ - lambda:CheckpointDurableExecution
+ - lambda:GetDurableExecutionState
+ Resource: !Sub 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${FunctionName}:*/durable-execution/*'
+ - DynamoDBCrudPolicy:
+ TableName: !Ref OrdersTable
+```
+
+## Customization
+
+### Adjust Wait Time
+
+Modify the wait duration in `src/index.js`:
+
+```javascript
+await context.wait({ seconds: 3600 }); // Wait 1 hour
+```
+
+### Add More Steps
+
+Add additional processing steps:
+
+```javascript
+await context.step('send-notification', async () => {
+ console.log('Sending notification');
+ // Send email/SMS notification
+});
+```
+
+### Integrate Real Services
+
+Replace simulation code with actual service calls:
+
+```javascript
+await context.step('process-payment', async () => {
+ const stripe = require('stripe')(process.env.STRIPE_KEY);
+ return await stripe.charges.create({
+ amount: order.total * 100,
+ currency: 'usd',
+ customer: order.customerId
+ });
+});
+```
+
+### Modify Execution Timeout
+
+Update the durable configuration when creating the function:
+
+```yaml
+DurableConfig:
+ ExecutionTimeout: 172800 # 48 hours
+ RetentionPeriodInDays: 14
+```
+
+## Monitoring
+
+### CloudWatch Metrics
+
+Monitor durable execution metrics:
+- `DurableExecutionStarted`
+- `DurableExecutionCompleted`
+- `DurableExecutionFailed`
+- `DurableExecutionCheckpointCreated`
+
+### CloudWatch Logs
+
+Look for log entries with `[DURABLE_EXECUTION]` prefix to track:
+- Checkpoint creation
+- Replay events
+- Step execution
+
+### X-Ray Tracing
+
+Enable X-Ray tracing in the SAM template:
+
+```yaml
+Tracing: Active
+```
+
+## Cleanup
+
+Delete the stack:
+
+```bash
+sam delete --region us-east-2
+```
+
+Or via AWS CLI:
+
+```bash
+aws cloudformation delete-stack --stack-name lambda-durable-order-processing --region us-east-2
+```
+
+## Cost Considerations
+
+- **Lambda**: Pay per invocation and execution time
+- **DynamoDB**: Pay-per-request pricing
+- **API Gateway**: Pay per API call
+- **Durable Execution**: Checkpoint storage costs (minimal)
+- **Wait States**: No compute charges during waits
+
+## Learn More
+
+- [Lambda Durable Functions Documentation](https://docs.aws.amazon.com/lambda/latest/dg/durable-functions.html)
+- [Durable Execution SDK (JavaScript)](https://github.com/aws/aws-durable-execution-sdk-js)
+- [AWS SAM Documentation](https://docs.aws.amazon.com/serverless-application-model/)
+
+---
+
+Copyright 2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
+
+SPDX-License-Identifier: MIT-0
diff --git a/lambda-durable-order-processing-sam/architecture.png b/lambda-durable-order-processing-sam/architecture.png
new file mode 100644
index 000000000..e8f7635c9
Binary files /dev/null and b/lambda-durable-order-processing-sam/architecture.png differ
diff --git a/lambda-durable-order-processing-sam/example-pattern.json b/lambda-durable-order-processing-sam/example-pattern.json
new file mode 100644
index 000000000..7c3748b10
--- /dev/null
+++ b/lambda-durable-order-processing-sam/example-pattern.json
@@ -0,0 +1,68 @@
+{
+ "title": "Order Processing Workflow with Lambda Durable Functions",
+ "description": "Production-ready 17-step order processing workflow using Lambda Durable Functions with automatic checkpointing, long-running waits, and state persistence",
+ "language": "Node.js",
+ "level": "300",
+ "framework": "AWS SAM",
+ "introBox": {
+ "headline": "How it works",
+ "text": [
+ "This pattern demonstrates a production-ready order processing workflow with 17 steps using Lambda Durable Functions.",
+ "The workflow includes validation, payment processing, fraud checks, credit checks (for high-value orders), inventory management, and shipping coordination.",
+ "Durable execution enables long-running waits (5 minutes for warehouse processing, 3 minutes for carrier pickup) without consuming compute resources.",
+ "Each step is automatically checkpointed, allowing the workflow to survive interruptions and resume from the last successful step.",
+ "The pattern uses a dual-function architecture: async durable function for order processing and sync non-durable function for real-time status queries.",
+ "Order state is persisted in DynamoDB with real-time status updates throughout the 17-step workflow."
+ ]
+ },
+ "gitHub": {
+ "template": {
+ "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/lambda-durable-order-processing-sam",
+ "templateURL": "serverless-patterns/lambda-durable-order-processing-sam",
+ "projectFolder": "lambda-durable-order-processing-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 JavaScript",
+ "link": "https://github.com/aws/aws-durable-execution-sdk-js"
+ },
+ {
+ "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": [
+ "Note: Lambda Durable Functions are currently available in us-east-2 (Ohio) region only.",
+ "cd src && npm install && cd ..",
+ "sam build",
+ "sam deploy --guided --region us-east-2"
+ ]
+ },
+ "testing": {
+ "text": [
+ "See the GitHub repo for detailed testing instructions."
+ ]
+ },
+ "cleanup": {
+ "text": [
+ "Delete the stack: sam delete --region us-east-2."
+ ]
+ },
+ "authors": [
+ {
+ "name": "Abhishek Agawane",
+ "image": "https://drive.google.com/file/d/1E-5koDaKEaMUtOctX32I9TLwfh3kgpAq/view?usp=drivesdk",
+ "bio": "Abhishek Agawane is a Security Consultant at Amazon Web Services with more than 8 years of industry experience. He helps organizations architect resilient, secure, and efficient cloud environments, guiding them through complex challenges and large-scale infrastructure transformations. He has helped numerous organizations enhance their cloud operations through targeted optimizations, robust architectures, and best-practice implementations.",
+ "linkedin": "https://www.linkedin.com/in/agawabhi/"
+ }
+ ]
+}
diff --git a/lambda-durable-order-processing-sam/lambda-durable-order-processing-sam.json b/lambda-durable-order-processing-sam/lambda-durable-order-processing-sam.json
new file mode 100644
index 000000000..c5b3aed6a
--- /dev/null
+++ b/lambda-durable-order-processing-sam/lambda-durable-order-processing-sam.json
@@ -0,0 +1,96 @@
+{
+ "title": "Order Processing with AWS Lambda Durable Functions",
+ "description": "Order processing workflow using Lambda Durable Functions with automatic checkpointing, long-running waits, and state persistence",
+ "language": "Node.js",
+ "level": "300",
+ "framework": "AWS SAM",
+ "introBox": {
+ "headline": "How it works",
+ "text": [
+ "This pattern demonstrates an order processing workflow using Lambda Durable Functions.",
+ "The workflow includes validation, payment processing, fraud checks, credit checks (for high-value orders), inventory management, and shipping coordination.",
+ "Durable execution enables long-running waits (5 minutes for warehouse processing, 3 minutes for carrier pickup) without consuming compute resources.",
+ "Each step is automatically checkpointed, allowing the workflow to survive interruptions and resume from the last successful step.",
+ "The pattern uses a dual-function architecture: async durable function for order processing and sync non-durable function for real-time status queries.",
+ "Order state is persisted in Amazon DynamoDB with real-time status updates throughout the 17-step workflow."
+ ]
+ },
+ "gitHub": {
+ "template": {
+ "repoURL": "https://github.com/aws-samples/serverless-patterns/tree/main/lambda-durable-order-processing-sam",
+ "templateURL": "serverless-patterns/lambda-durable-order-processing-sam",
+ "projectFolder": "lambda-durable-order-processing-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 JavaScript",
+ "link": "https://github.com/aws/aws-durable-execution-sdk-js"
+ },
+ {
+ "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": [
+ "Note: Lambda Durable Functions are currently available in us-east-2 (Ohio) region only.",
+ "cd src && npm install && cd ..",
+ "sam build",
+ "sam deploy --guided --region us-east-2"
+ ]
+ },
+ "testing": {
+ "text": [
+ "See the GitHub repo for detailed testing instructions."
+ ]
+ },
+ "cleanup": {
+ "text": [
+ "Delete the stack: sam delete --region us-east-2."
+ ]
+ },
+ "authors": [
+ {
+ "name": "Abhishek Agawane",
+ "image": "https://drive.google.com/file/d/1E-5koDaKEaMUtOctX32I9TLwfh3kgpAq/view?usp=drivesdk",
+ "bio": "Abhishek Agawane is a Security Consultant at Amazon Web Services with more than 8 years of industry experience. He helps organizations architect resilient, secure, and efficient cloud environments, guiding them through complex challenges and large-scale infrastructure transformations. He has helped numerous organizations enhance their cloud operations through targeted optimizations, robust architectures, and best-practice implementations.",
+ "linkedin": "agawabhi"
+ }
+ ],
+ "patternArch": {
+ "icon1": {
+ "x": 20,
+ "y": 50,
+ "service": "apigw",
+ "label": "API Gateway REST API"
+ },
+ "icon2": {
+ "x": 50,
+ "y": 50,
+ "service": "lambda",
+ "label": "AWS Lambda"
+ },
+ "line1": {
+ "from": "icon1",
+ "to": "icon2"
+ },
+ "icon3": {
+ "x": 80,
+ "y": 50,
+ "service": "dynamodb",
+ "label": "Amazon DynamoDB"
+ },
+ "line2": {
+ "from": "icon2",
+ "to": "icon3"
+ }
+ }
+}
diff --git a/lambda-durable-order-processing-sam/src/index.js b/lambda-durable-order-processing-sam/src/index.js
new file mode 100644
index 000000000..d30fabb27
--- /dev/null
+++ b/lambda-durable-order-processing-sam/src/index.js
@@ -0,0 +1,408 @@
+const { withDurableExecution } = require('@aws/durable-execution-sdk-js');
+const { DynamoDBClient } = require('@aws-sdk/client-dynamodb');
+const { DynamoDBDocumentClient, PutCommand, UpdateCommand } = require('@aws-sdk/lib-dynamodb');
+
+const dynamoClient = new DynamoDBClient({});
+const docClient = DynamoDBDocumentClient.from(dynamoClient);
+const ORDERS_TABLE = process.env.ORDERS_TABLE;
+
+/**
+ * Order Processing Durable Function
+ *
+ * This function demonstrates a multi-step order processing workflow:
+ * 1. Validate order
+ * 2. Check inventory
+ * 3. Process payment
+ * 4. Reserve inventory
+ * 5. Wait for fulfillment preparation
+ * 6. Ship order
+ * 7. Send confirmation
+ */
+exports.handler = withDurableExecution(async (event, context) => {
+ console.log('Starting order processing', { event });
+
+ // Parse order data - orderId comes from API Gateway template
+ const orderId = event.orderId || `order-${Date.now()}`;
+ const body = typeof event.body === 'string' ? JSON.parse(event.body) : event.body;
+ const order = { ...body, orderId };
+
+ try {
+ // Step 1: Validate Order
+ const validatedOrder = await context.step('validate-order', async () => {
+ console.log('Validating order', { orderId });
+
+ // Simulate validation logic
+ if (!order.items || order.items.length === 0) {
+ throw new Error('Order must contain at least one item');
+ }
+
+ if (!order.customerId) {
+ throw new Error('Customer ID is required');
+ }
+
+ // Calculate total
+ const total = order.items.reduce((sum, item) => {
+ return sum + (item.price * item.quantity);
+ }, 0);
+
+ const validated = {
+ ...order,
+ orderId,
+ total,
+ status: 'validated',
+ validatedAt: new Date().toISOString()
+ };
+
+ // Save to DynamoDB
+ await docClient.send(new PutCommand({
+ TableName: ORDERS_TABLE,
+ Item: validated
+ }));
+
+ return validated;
+ });
+
+ // Step 2: Check Inventory
+ const inventoryCheck = await context.step('check-inventory', async () => {
+ console.log('Checking inventory', { orderId });
+
+ // Simulate inventory check
+ const available = validatedOrder.items.every(item => {
+ // Simulate: 90% chance items are in stock
+ return Math.random() > 0.1;
+ });
+
+ if (!available) {
+ throw new Error('Insufficient inventory');
+ }
+
+ await updateOrderStatus(orderId, 'inventory-checked');
+
+ return {
+ available: true,
+ checkedAt: new Date().toISOString()
+ };
+ });
+
+ // Step 3: Process Payment
+ const paymentResult = await context.step('process-payment', async () => {
+ console.log('Processing payment', { orderId, amount: validatedOrder.total });
+
+ // Simulate payment processing
+ // In real scenario, this would call a payment gateway
+ const paymentId = `pay-${Date.now()}`;
+
+ // Simulate: 95% success rate
+ if (Math.random() < 0.05) {
+ throw new Error('Payment declined');
+ }
+
+ await updateOrderStatus(orderId, 'payment-processed');
+
+ return {
+ paymentId,
+ amount: validatedOrder.total,
+ status: 'success',
+ processedAt: new Date().toISOString()
+ };
+ });
+
+ // Step 4: Reserve Inventory
+ const reservation = await context.step('reserve-inventory', async () => {
+ console.log('Reserving inventory', { orderId });
+
+ // Simulate inventory reservation
+ const reservationId = `res-${Date.now()}`;
+
+ await updateOrderStatus(orderId, 'inventory-reserved');
+
+ return {
+ reservationId,
+ items: validatedOrder.items,
+ reservedAt: new Date().toISOString()
+ };
+ });
+
+ // Step 5: Fraud Check (parallel with credit check)
+ const fraudCheck = await context.step('fraud-check', async () => {
+ console.log('Running fraud detection', { orderId });
+
+ // Simulate fraud detection analysis
+ const riskScore = Math.random() * 100;
+ const isFraudulent = riskScore > 95;
+
+ if (isFraudulent) {
+ throw new Error('Order flagged as fraudulent');
+ }
+
+ await updateOrderStatus(orderId, 'fraud-checked');
+
+ return {
+ riskScore,
+ status: 'passed',
+ checkedAt: new Date().toISOString()
+ };
+ });
+
+ // Step 6: Credit Check
+ const creditCheck = await context.step('credit-check', async () => {
+ console.log('Checking customer credit', { orderId });
+
+ // Simulate credit check for high-value orders
+ if (validatedOrder.total > 1000) {
+ const creditScore = Math.floor(Math.random() * 300) + 500;
+
+ if (creditScore < 600) {
+ throw new Error('Insufficient credit score');
+ }
+
+ return {
+ creditScore,
+ approved: true,
+ checkedAt: new Date().toISOString()
+ };
+ }
+
+ return { skipped: true, reason: 'Order value below threshold' };
+ });
+
+ // Step 7: Generate Invoice
+ const invoice = await context.step('generate-invoice', async () => {
+ console.log('Generating invoice', { orderId });
+
+ const invoiceId = `INV-${Date.now()}`;
+ const invoiceData = {
+ invoiceId,
+ orderId,
+ customerId: validatedOrder.customerId,
+ items: validatedOrder.items,
+ subtotal: validatedOrder.total,
+ tax: validatedOrder.total * 0.08,
+ total: validatedOrder.total * 1.08,
+ generatedAt: new Date().toISOString()
+ };
+
+ await updateOrderStatus(orderId, 'invoice-generated');
+
+ return invoiceData;
+ });
+
+ // Step 8: Wait for warehouse processing (showcases long wait without compute charges)
+ console.log('Waiting for warehouse processing', { orderId });
+ await updateOrderStatus(orderId, 'awaiting-warehouse');
+ await context.wait({ seconds: 300 }); // 5 minutes - in production could be hours
+
+ // Step 9: Pick Items from Warehouse
+ const pickingResult = await context.step('pick-items', async () => {
+ console.log('Picking items from warehouse', { orderId });
+
+ const pickedItems = validatedOrder.items.map(item => ({
+ ...item,
+ binLocation: `BIN-${Math.floor(Math.random() * 1000)}`,
+ pickedBy: `PICKER-${Math.floor(Math.random() * 50)}`,
+ pickedAt: new Date().toISOString()
+ }));
+
+ await updateOrderStatus(orderId, 'items-picked');
+
+ return {
+ items: pickedItems,
+ completedAt: new Date().toISOString()
+ };
+ });
+
+ // Step 10: Quality Check
+ const qualityCheck = await context.step('quality-check', async () => {
+ console.log('Performing quality check', { orderId });
+
+ // Simulate quality inspection
+ const passedQC = Math.random() > 0.02; // 98% pass rate
+
+ if (!passedQC) {
+ throw new Error('Quality check failed - items damaged');
+ }
+
+ await updateOrderStatus(orderId, 'quality-checked');
+
+ return {
+ passed: true,
+ inspector: `QC-${Math.floor(Math.random() * 20)}`,
+ checkedAt: new Date().toISOString()
+ };
+ });
+
+ // Step 11: Package Order
+ const packaging = await context.step('package-order', async () => {
+ console.log('Packaging order', { orderId });
+
+ const packageId = `PKG-${Date.now()}`;
+ const weight = validatedOrder.items.reduce((sum, item) => sum + (item.quantity * 2), 0);
+
+ await updateOrderStatus(orderId, 'packaged');
+
+ return {
+ packageId,
+ weight: `${weight} lbs`,
+ dimensions: '12x10x8 inches',
+ packagedBy: `PACKER-${Math.floor(Math.random() * 30)}`,
+ packagedAt: new Date().toISOString()
+ };
+ });
+
+ // Step 12: Generate Shipping Label
+ const shippingLabel = await context.step('generate-shipping-label', async () => {
+ console.log('Generating shipping label', { orderId });
+
+ const trackingNumber = `TRK-${Date.now()}-${Math.random().toString(36).substring(2, 11).toUpperCase()}`;
+ const carrier = validatedOrder.total > 500 ? 'ExpressShip' : 'StandardShip';
+
+ return {
+ trackingNumber,
+ carrier,
+ labelUrl: `https://shipping.example.com/labels/${trackingNumber}`,
+ generatedAt: new Date().toISOString()
+ };
+ });
+
+ // Step 13: Wait for carrier pickup (another long wait)
+ console.log('Waiting for carrier pickup', { orderId });
+ await updateOrderStatus(orderId, 'awaiting-pickup');
+ await context.wait({ seconds: 180 }); // 3 minutes - in production could be hours
+
+ // Step 14: Ship Order
+ const shipment = await context.step('ship-order', async () => {
+ console.log('Order shipped', { orderId });
+
+ await updateOrderStatus(orderId, 'shipped');
+
+ return {
+ ...shippingLabel,
+ estimatedDelivery: new Date(Date.now() + 3 * 24 * 60 * 60 * 1000).toISOString(),
+ shippedAt: new Date().toISOString()
+ };
+ });
+
+ // Step 15: Send Customer Notifications (parallel notifications)
+ const notifications = await context.step('send-notifications', async () => {
+ console.log('Sending customer notifications', { orderId });
+
+ // Simulate sending multiple notifications
+ const emailNotification = {
+ type: 'email',
+ recipient: order.customerEmail || 'customer@example.com',
+ subject: `Order ${orderId} Shipped - Tracking: ${shippingLabel.trackingNumber}`,
+ sentAt: new Date().toISOString()
+ };
+
+ const smsNotification = {
+ type: 'sms',
+ recipient: order.customerPhone || '+1234567890',
+ message: `Your order ${orderId} has shipped! Track: ${shippingLabel.trackingNumber}`,
+ sentAt: new Date().toISOString()
+ };
+
+ return {
+ email: emailNotification,
+ sms: smsNotification
+ };
+ });
+
+ // Step 16: Update Loyalty Points
+ const loyaltyUpdate = await context.step('update-loyalty-points', async () => {
+ console.log('Updating loyalty points', { orderId });
+
+ const pointsEarned = Math.floor(validatedOrder.total * 0.1); // 10% back in points
+
+ return {
+ customerId: validatedOrder.customerId,
+ pointsEarned,
+ newBalance: pointsEarned, // In production, would fetch and add to existing balance
+ updatedAt: new Date().toISOString()
+ };
+ });
+
+ // Step 17: Complete Order
+ const completion = await context.step('complete-order', async () => {
+ console.log('Completing order', { orderId });
+
+ await updateOrderStatus(orderId, 'completed');
+
+ return {
+ completedAt: new Date().toISOString(),
+ totalProcessingTime: Date.now() - parseInt(orderId.split('-')[1])
+ };
+ });
+
+ // Return comprehensive result
+ const result = {
+ orderId,
+ status: 'completed',
+ order: validatedOrder,
+ payment: paymentResult,
+ fraudCheck,
+ creditCheck,
+ invoice,
+ picking: pickingResult,
+ qualityCheck,
+ packaging,
+ shipment,
+ notifications,
+ loyaltyPoints: loyaltyUpdate,
+ completion,
+ summary: {
+ totalSteps: 17,
+ totalWaitTime: '8 minutes (480 seconds)',
+ processingTime: `${completion.totalProcessingTime}ms`
+ }
+ };
+
+ console.log('Order processing completed successfully', { orderId, totalSteps: 17 });
+ return result;
+
+ } catch (error) {
+ console.error('Order processing failed', { orderId, error: error.message });
+
+ // Compensation logic - rollback changes
+ await context.step('compensate', async () => {
+ console.log('Running compensation logic', { orderId });
+
+ await updateOrderStatus(orderId, 'failed', error.message);
+
+ // In production, you would:
+ // - Refund payment if processed
+ // - Release inventory reservation
+ // - Notify customer of failure
+
+ return {
+ compensated: true,
+ reason: error.message
+ };
+ });
+
+ throw error;
+ }
+});
+
+/**
+ * Helper function to update order status in DynamoDB
+ */
+async function updateOrderStatus(orderId, status, errorMessage = null) {
+ const updateExpression = errorMessage
+ ? 'SET #status = :status, errorMessage = :error, updatedAt = :updatedAt'
+ : 'SET #status = :status, updatedAt = :updatedAt';
+
+ const expressionAttributeValues = errorMessage
+ ? { ':status': status, ':error': errorMessage, ':updatedAt': new Date().toISOString() }
+ : { ':status': status, ':updatedAt': new Date().toISOString() };
+
+ await docClient.send(new UpdateCommand({
+ TableName: ORDERS_TABLE,
+ Key: { orderId },
+ UpdateExpression: updateExpression,
+ ExpressionAttributeNames: {
+ '#status': 'status'
+ },
+ ExpressionAttributeValues: expressionAttributeValues
+ }));
+}
+
diff --git a/lambda-durable-order-processing-sam/src/package.json b/lambda-durable-order-processing-sam/src/package.json
new file mode 100644
index 000000000..ac34e40e5
--- /dev/null
+++ b/lambda-durable-order-processing-sam/src/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "lambda-durable-order-processing",
+ "version": "1.0.0",
+ "description": "Order processing workflow using Lambda Durable Functions",
+ "main": "index.js",
+ "scripts": {
+ "test": "echo \"Error: no test specified\" && exit 1"
+ },
+ "dependencies": {
+ "@aws/durable-execution-sdk-js": "^1.0.0",
+ "@aws-sdk/client-dynamodb": "^3.0.0",
+ "@aws-sdk/lib-dynamodb": "^3.0.0",
+ "@aws-sdk/client-lambda": "^3.0.0"
+ },
+ "keywords": [
+ "aws",
+ "lambda",
+ "durable-functions",
+ "serverless",
+ "order-processing"
+ ],
+ "author": "",
+ "license": "MIT-0"
+}
diff --git a/lambda-durable-order-processing-sam/src/status.js b/lambda-durable-order-processing-sam/src/status.js
new file mode 100644
index 000000000..326728332
--- /dev/null
+++ b/lambda-durable-order-processing-sam/src/status.js
@@ -0,0 +1,70 @@
+const { DynamoDBClient } = require('@aws-sdk/client-dynamodb');
+const { DynamoDBDocumentClient, GetCommand } = require('@aws-sdk/lib-dynamodb');
+
+const dynamoClient = new DynamoDBClient({});
+const docClient = DynamoDBDocumentClient.from(dynamoClient);
+const ORDERS_TABLE = process.env.ORDERS_TABLE;
+
+/**
+ * Order Status Function (Non-Durable)
+ *
+ * This is a separate, regular Lambda function for checking order status.
+ * It queries DynamoDB directly without invoking the durable function.
+ */
+exports.handler = async (event) => {
+ console.log('Checking order status', { event });
+
+ try {
+ const orderId = event.pathParameters?.orderId;
+
+ if (!orderId) {
+ return {
+ statusCode: 400,
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ error: 'Order ID is required' })
+ };
+ }
+
+ const result = await docClient.send(new GetCommand({
+ TableName: ORDERS_TABLE,
+ Key: { orderId }
+ }));
+
+ if (!result.Item) {
+ return {
+ statusCode: 404,
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ error: 'Order not found',
+ orderId
+ })
+ };
+ }
+
+ return {
+ statusCode: 200,
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ orderId: result.Item.orderId,
+ status: result.Item.status,
+ customerId: result.Item.customerId,
+ customerEmail: result.Item.customerEmail,
+ total: result.Item.total,
+ items: result.Item.items,
+ createdAt: result.Item.validatedAt || result.Item.updatedAt,
+ lastUpdated: result.Item.updatedAt,
+ errorMessage: result.Item.errorMessage
+ })
+ };
+ } catch (error) {
+ console.error('Error getting order status', { error });
+ return {
+ statusCode: 500,
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ error: 'Failed to get order status',
+ message: error.message
+ })
+ };
+ }
+};
diff --git a/lambda-durable-order-processing-sam/template.yaml b/lambda-durable-order-processing-sam/template.yaml
new file mode 100644
index 000000000..29bdac282
--- /dev/null
+++ b/lambda-durable-order-processing-sam/template.yaml
@@ -0,0 +1,148 @@
+AWSTemplateFormatVersion: '2010-09-09'
+Transform: AWS::Serverless-2016-10-31
+Description: Order Processing Workflow using AWS Lambda Durable Functions (uksb-1tthgi812) (tag:lambda-durable-order-processing-sam)
+
+Globals:
+ Function:
+ Timeout: 900
+ Runtime: nodejs22.x
+ Architectures:
+ - arm64
+ Environment:
+ Variables:
+ ORDERS_TABLE: !Ref OrdersTable
+
+Resources:
+ # DynamoDB Table for Orders
+ OrdersTable:
+ Type: AWS::DynamoDB::Table
+ Properties:
+ TableName: !Sub '${AWS::StackName}-orders'
+ BillingMode: PAY_PER_REQUEST
+ AttributeDefinitions:
+ - AttributeName: orderId
+ AttributeType: S
+ KeySchema:
+ - AttributeName: orderId
+ KeyType: HASH
+ StreamSpecification:
+ StreamViewType: NEW_AND_OLD_IMAGES
+
+ # Order Processing Durable Function
+ OrderProcessingFunction:
+ Type: AWS::Serverless::Function
+ Properties:
+ CodeUri: src/
+ Handler: index.handler
+ Timeout: 120
+ AutoPublishAlias: live
+ DurableConfig:
+ ExecutionTimeout: 86400 # 24 hours
+ RetentionPeriodInDays: 7
+ Policies:
+ - DynamoDBCrudPolicy:
+ TableName: !Ref OrdersTable
+ - Statement:
+ - Effect: Allow
+ Action:
+ - lambda:CheckpointDurableExecution
+ Resource: !Sub 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${AWS::StackName}-OrderProcessingFunction-*'
+
+ # Order Status Function (Non-Durable)
+ OrderStatusFunction:
+ Type: AWS::Serverless::Function
+ Properties:
+ CodeUri: src/
+ Handler: status.handler
+ Timeout: 30
+ Policies:
+ - DynamoDBReadPolicy:
+ TableName: !Ref OrdersTable
+
+ # API Gateway
+ OrderApi:
+ Type: AWS::Serverless::Api
+ Properties:
+ StageName: prod
+ Cors:
+ AllowMethods: "'POST, GET, OPTIONS'"
+ AllowHeaders: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key'"
+ AllowOrigin: "'*'"
+ DefinitionBody:
+ openapi: 3.0.1
+ paths:
+ /orders:
+ post:
+ responses:
+ '202':
+ description: Order accepted
+ x-amazon-apigateway-integration:
+ type: aws
+ httpMethod: POST
+ uri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${OrderProcessingFunction.Arn}:live/invocations'
+ requestParameters:
+ integration.request.header.X-Amz-Invocation-Type: "'Event'"
+ requestTemplates:
+ application/json: |
+ #set($orderId = "order-$context.requestTimeEpoch")
+ {
+ "orderId": "$orderId",
+ "body": $input.json('$')
+ }
+ responses:
+ default:
+ statusCode: '202'
+ responseTemplates:
+ application/json: |
+ #set($orderId = "order-$context.requestTimeEpoch")
+ {
+ "message": "Order processing initiated",
+ "orderId": "$orderId"
+ }
+ passthroughBehavior: never
+ /orders/{orderId}:
+ get:
+ parameters:
+ - name: orderId
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: Order status
+ x-amazon-apigateway-integration:
+ type: aws_proxy
+ httpMethod: POST
+ uri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${OrderStatusFunction.Arn}/invocations'
+ passthroughBehavior: when_no_match
+
+ # Lambda Permissions for API Gateway
+ OrderProcessingFunctionInvokePermission:
+ Type: AWS::Lambda::Permission
+ Properties:
+ FunctionName: !Ref OrderProcessingFunction.Alias
+ Action: lambda:InvokeFunction
+ Principal: apigateway.amazonaws.com
+ SourceArn: !Sub 'arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${OrderApi}/*/POST/orders'
+
+ OrderStatusFunctionInvokePermission:
+ Type: AWS::Lambda::Permission
+ Properties:
+ FunctionName: !Ref OrderStatusFunction
+ Action: lambda:InvokeFunction
+ Principal: apigateway.amazonaws.com
+ SourceArn: !Sub 'arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${OrderApi}/*/GET/orders/*'
+
+Outputs:
+ OrderApiEndpoint:
+ Description: API Gateway endpoint URL for order processing
+ Value: !Sub 'https://${OrderApi}.execute-api.${AWS::Region}.amazonaws.com/prod'
+
+ OrderProcessingFunctionArn:
+ Description: Order Processing Durable Function ARN
+ Value: !GetAtt OrderProcessingFunction.Arn
+
+ OrdersTableName:
+ Description: DynamoDB table name for orders
+ Value: !Ref OrdersTable
diff --git a/lambda-durable-order-processing-sam/test-orders.json b/lambda-durable-order-processing-sam/test-orders.json
new file mode 100644
index 000000000..5cb93e0c4
--- /dev/null
+++ b/lambda-durable-order-processing-sam/test-orders.json
@@ -0,0 +1,50 @@
+{
+ "lowValueOrder": {
+ "customerId": "CUST-001",
+ "customerEmail": "customer1@example.com",
+ "items": [
+ {
+ "productId": "BOOK-001",
+ "name": "Programming Book",
+ "quantity": 2,
+ "price": 45.99
+ }
+ ]
+ },
+ "highValueOrder": {
+ "customerId": "CUST-002",
+ "customerEmail": "customer2@example.com",
+ "items": [
+ {
+ "productId": "SERVER-001",
+ "name": "Enterprise Server",
+ "quantity": 1,
+ "price": 3500.00
+ }
+ ]
+ },
+ "multiItemOrder": {
+ "customerId": "CUST-003",
+ "customerEmail": "customer3@example.com",
+ "items": [
+ {
+ "productId": "LAPTOP-001",
+ "name": "Gaming Laptop",
+ "quantity": 1,
+ "price": 1299.99
+ },
+ {
+ "productId": "MOUSE-001",
+ "name": "Wireless Mouse",
+ "quantity": 2,
+ "price": 29.99
+ },
+ {
+ "productId": "KEYBOARD-001",
+ "name": "Mechanical Keyboard",
+ "quantity": 1,
+ "price": 149.99
+ }
+ ]
+ }
+}