Stateful Serverless Patterns
Long jobs and sagas on stateless compute
Functions are stateless; durable workflows (Step Functions, Logic Apps, Workflows) bring state as orchestrated sequences with retries, human approval, and exact progress tracking. Long-running, resumable, auditable serverless — built from stateless bricks.
What you will learn
- Model a long job as a state machine (steps, states, retries)
- Compare direct orchestration vs choreography for sagas
- Handle resume/restart and human approval in workflows
An orchestrator (Step Functions, Durable Functions runtime ~ SubOrchestrator, GCP Workflows) tracks a JSON state between steps. Each step invokes a stateless function; the machine remembers where it stopped and can sleep/fail retry/resume — no server holds the state.
What is this?
Primitives: states (task, wait, choice, parallel, map, fail, succeed, pass), retry/catch per state, timeout, and the input/output JSON contract between steps. Express vs Standard (AWS: standard exact-once, express high-throughput/at-least-once; Azure Durable: activity/orchestration/entity types; GCP Workflows: steps/join/retry policies). Durable Entities / Durable Objects: stateful actors on serverless (per-entity key concurrency, commands, reminders). Orchestration vs choreography (sagas: orchestrator decides compensation order; choreography: each service compensates its own — fewer points but harder to reason about). Observability/audit: every state transition logged/exported.
Why do you need it?
- State machines turn multi-step jobs into inspectable, resumable graph state.
- Retry/compensation live in the workflow, not re-implemented per function.
- Human approval and time-gated events are first-class states.
- Durable actors compress many tiny stateful services into one consistent system.
Mental model
A flight itinerary with checkpoints, stopovers and rebooking rules
Workflow execution state
Each leg (state) is followed by a checkpoint; if the airline (function) fails, the itinerary (workflow) has a rebooking rule and records exactly where you are.
How it works
- A workflow definition (ASL/JSON/YAML) declares states and their transitions.
- Each invocation starts a workflow instance with an input payload.
- A task state calls a function, captures its output, feeds the next state.
- Failures with retry policy retry; after budget → catch → compensation/fail.
- Standard execs persist execution history; instantiating a resume reads history.
A checkout-flow state machine.
Examples
ASL sketch of a saga step
"Charge": { "Type": "Task", "Resource": "arn:aws:states:::lambda:invoke", "Parameters": { "FunctionName": "charge", "Payload.$": "$" }, "Retry": [{ "ErrorEquals": ["TransientError"], "MaxAttempts": 3, "IntervalSeconds": 2 }], "Catch": [{ "ErrorEquals": ["States.ALL"], "Next": "Refund" }]}One JSON state describes charge + retry + compensation jump — behavior that would otherwise be bespoke code in a service.
In production
- ETL orchestration with exponential retry and per-step alerting.
- Checkout: reserve → charge → ship, compensating refund on failure.
- Onboarding with a two-week admin-approval wait state.
- Durable entities for per-user balances with command-based serialization.
Best practices
- Keep state transitions small and typed; pass only what the next step needs.
- Use Standard executions where you need audit/retry; Express for fire-and-forget high volume.
- Define compensation steps explicitly for every unsafe transition.
- Bound function calls by the workflow's own timeout/lambdas instead of infinite retries.
- Version workflow definitions; treat schema changes as migration events.
Common mistakes
- Reusing choreography code (compensation lives in consumer) under orchestrator names but without ordering.
- Storing large payloads in the execution JSON — costs and slows history.
- Trying to make workflows do fine-grained CPU work; that belongs in functions.
- Assuming retry is exactly-once; standard is near-solid, express is at-least-once.
Debugging tips
- Pull the execution history with state input/output for each transition — the timeline is the debugger.
- Distinguish retry loops (state x attempts N) from infinite loops (choice misconfigured).
- Check history size limits; trim payloads your step functions carry.
- Expose step duration + transition counts as metrics to spot hotspot states.
Interview checkpoint
Hands-on lab
- Author a workflow with task + retry + compensation
- Run it, kill a step, and observe retry/catch semantics
- Inspect execution history as the ultimate debugger
Orchestrate a Resumable Job in a State Machine
40 min · advanced
Quick quiz
Which state primitive adds fan-out?
Express/Standard executions differ primarily in: