Account concurrency is a shared fate pool. One tenant’s report export or AI agent fan-out will starve checkout if you leave every function unreserved. Bulkheads via reserved concurrency are the unfair advantage: explicit partitions for critical paths, unreserved headroom for bursty best-effort work, and alarms before the pool hits zero.
⚡ TL;DR: Reserve concurrency for auth, checkout, and payment webhooks first. Cap noisy neighbors (exports, backfills, agent tools) with low reserved ceilings or separate accounts. Leave unreserved headroom for spikes — reserved is subtracted from the account pool. Simulate noisy-neighbor drills. Tie agent backends to Lambda Warm Pools and sandboxes in Secure AI Sandboxes.
Mental model: reserved subtracts from the pool
Account limit L (e.g. 1000)
Reserved sum R across functions
Unreserved capacity = L - R
Function with reserved=50 can never exceed 50
Function with no reservation competes for L - R
// GOOD: critical path reserved; batch capped
await lambda.putFunctionConcurrency({
FunctionName: "checkout-api",
ReservedConcurrentExecutions: 200,
});
await lambda.putFunctionConcurrency({
FunctionName: "tenant-export",
ReservedConcurrentExecutions: 20, // hard bulkhead
});
// BAD: reserve 900 of 1000 for "important" batch jobs
// leaves auth/checkout fighting over 100 unreserved
✅ Reserve the money path; cap the analytics path.
❌ Reserving almost everything “just in case” (destroys burst capacity).
Per-tenant isolation patterns
| Pattern | When | Tradeoff |
|---|---|---|
| Reserved concurrency per function | Feature-level bulkhead | Coarse |
| Separate functions per noisy tenant tier | Enterprise isolation | Ops overhead |
| SQS max concurrency on ESM | Async pipelines | Backpressure into queue |
| Provisioned + reserved | Latency + isolation | Cost |
// Event source mapping max concurrency as a second bulkhead
await lambda.updateEventSourceMapping({
UUID: esmId,
ScalingConfig: { MaximumConcurrency: 10 },
});
For multi-tenant SaaS, do not invent “dynamic reserved concurrency per tenant” on every request — use queue depth, per-tenant rate limits, and tiered function aliases instead.
Drill the failure mode
# Synthetic load on export while measuring checkout Availability + Throttles
aws cloudwatch put-metric-alarm --alarm-name checkout-throttles \
--metric-name Throttles --namespace AWS/Lambda \
--dimensions Name=FunctionName,Value=checkout-api \
--threshold 1 --comparison-operator GreaterThanOrEqualToThreshold \
--evaluation-periods 1 --statistic Sum --period 60
If checkout throttles while export is healthy, your bulkhead math is inverted.
Closing checklist
- [ ] Money-path functions have reserved concurrency documented in an ADR
- [ ] Noisy jobs capped (reserved low or ESM max concurrency)
- [ ] Sum(reserved) leaves intentional unreserved headroom
- [ ] Alarms on Throttles for critical functions
- [ ] Quarterly noisy-neighbor game day
- [ ] Agent/tool Lambdas isolated from interactive APIs
Related reading
- Lambda Warm Pools: Low-Latency Backends for Coding Agent Tools
- Secure AI Sandboxes: Ephemeral ECS Tasks for Agent Tool Execution
- Agent Tool Allowlists: Least Privilege for Filesystem and Shell Access
- Cross-Account Bedrock Access: Platform Teams Without Shared Keys
Last updated on September 11, 2026
Discover more from CheatCoders
Subscribe to get the latest posts sent to your email.
