Demonstration project of distributed patterns using AWS Serverless (Lambda, DynamoDB, Step Functions).
If you don't have credentials configured:
aws configureEnter:
- AWS Access Key ID
- AWS Secret Access Key
- Default region:
us-east-1 - Default output:
json
npm install# Deploy to dev (default)
npm run deploy
# Or specify stage
npm run deploy:dev
npm run deploy:prodThis will automatically create:
- ✅ Lambda Functions
- ✅ DynamoDB Tables (Orders, Outbox, Idempotency)
- ✅ Step Functions State Machine
- ✅ API Gateway endpoints
- ✅ Event Bus
- ✅ IAM Roles and permissions
After deployment, you'll see the API Gateway endpoint. Current example: https://ttn14lhvmi.execute-api.us-east-1.amazonaws.com/dev/orders
curl -X POST https://ttn14lhvmi.execute-api.us-east-1.amazonaws.com/dev/orders \
-H "Content-Type: application/json" \
-d '{
"customerId": "customer-123",
"items": [
{"productId": "laptop", "quantity": 1, "price": 1299.99}
]
}'Expected response:
{
"orderId": "generated-uuid",
"status": "PENDING",
"totalAmount": 1299.99,
"message": "Order created successfully"
}curl -X POST https://ttn14lhvmi.execute-api.us-east-1.amazonaws.com/dev/orders \
-H "Content-Type: application/json" \
-H "x-idempotency-key: customer-order-001" \
-d '{
"customerId": "customer-456",
"items": [
{"productId": "monitor", "quantity": 2, "price": 349.99}
]
}'✨ Feature: If you execute the same request with the same x-idempotency-key within 10 minutes:
- ✅ You'll receive the same response (same
orderId) - ✅ NO duplicate order will be created
- ✅ Protection against accidental retries
- ⏱️ After 10 minutes, the record expires and you can create a new order with the same key
Important note: Idempotency returns the original state (PENDING), not the state updated by the workflow. To get the current state, query GET /orders/{orderId}. See docs/IDEMPOTENCY.md for more details.
# Run complete test suite
./test-api.shThis script tests:
- Create order without idempotency
- Create order with idempotency (first time)
- Repeat request with same key (verifies it returns same orderId)
- Create order with new key (verifies it creates new order)
# View Lambda functions
aws lambda list-functions --query 'Functions[?contains(FunctionName, `distributed-patterns`)].FunctionName'
# View DynamoDB tables
aws dynamodb list-tables
# View orders
aws dynamodb scan --table-name distributed-patterns-demo-orders-table-devnpm run removesrc/
├── functions/
│ ├── order-service/ # API to create orders
│ ├── outbox-processor/ # Process Outbox events
│ └── workflow/ # Workflow functions
│ ├── reserve-inventory.ts
│ ├── process-payment.ts
│ ├── send-notification.ts
│ └── compensate.ts
└── utils/
├── db.ts # Shared DynamoDB client
└── types/ # TypeScript definitions
- Save order + event in a DynamoDB transaction
- Guarantees consistency between writes
- Prevents lost events
- Uses AWS Lambda Powertools for idempotency
- Header:
x-idempotency-key - TTL: 10 minutes
- Dedicated DynamoDB table for tracking
- Workflow: Reserve Inventory → Process Payment → Send Notification
- Compensation: If any step fails, executes rollback
- Refunds payment (clear TODOs for Stripe/payment gateway integration)
- Releases inventory (clear TODOs for inventory service API calls)
- Updates order status to FAILED
- Retry Logic: Automatic retries with exponential backoff
- See docs/COMPENSATION.md for production integration examples
- DynamoDB Streams detect new events
- Outbox Processor starts workflows automatically
- Decoupling between services
AWS Free Tier includes:
- Lambda: 1M requests/month free
- DynamoDB: 25GB storage free
- Step Functions: 4,000 state transitions/month free
For development, costs are practically $0.
# View function logs
sls logs -f createOrder --tail
# Invoke function locally (without deploying)
sls invoke local -f createOrder --data '{"body": "{...}"}'
# View stack info
sls info
# Export Step Function ASL
npm run export-asl