CMD Guide
HomeSystem DesignMicroservices Patterns

Introduction to Saga Pattern

Introduction to the Saga Pattern

Imagine placing an order on an e-commerce site. Behind that one click, three separate services must all succeed: Orders creates the order, Payments charges the card, and Inventory reserves the stock. In a monolith with one database, you'd wrap all three writes in a single ACID transaction: either everything commits or everything rolls back. But in microservices, each service owns its own database. There is no shared transaction that spans all three. So what happens when Payments succeeds but Inventory says "out of stock"? You've taken the customer's money (or put a hold on it) for something they'll never receive.

The tempting fix is a distributed transaction using two-phase commit (2PC), where a coordinator locks all three databases until everyone agrees to commit. This works, but it's poison for high-throughput systems: it holds locks across network hops, blocks if the coordinator crashes mid-flight, and couples the availability of every service to every other. The Saga pattern is the answer most large systems actually reach for. Instead of one big atomic transaction, a saga is a sequence of local transactions, each committing independently, with a matching compensating transaction that semantically undoes it if a later step fails.

How it works, precisely

A saga breaks a business operation into a series of steps T1, T2, ... Tn. Each Ti is a normal local ACID transaction inside one service's own database and commits immediately. For each Ti you define a compensating transaction Ci that semantically reverses its effect. If step Tk fails, the saga runs C(k-1), C(k-2), ... C1 in reverse order to unwind the work already done.

Crucially, compensation is semantic, not physical. You can't "roll back" a charge that already committed and possibly cleared; instead C issues a refund — a new forward transaction that offsets it. This means sagas provide ACD (Atomicity-ish via compensation, Consistency, Durability) but sacrifice Isolation: intermediate states are visible to other transactions. That lost isolation is the source of most saga hazards.

There are two coordination styles:

Two properties are non-negotiable: every step and every compensation must be idempotent (messages get redelivered), and the saga state must be durably persisted so it survives a crash and resumes.

A worked scenario with numbers

Say the checkout service handles 2,000 orders/sec at peak. A 2PC across Orders, Payments, and Inventory would hold row locks in all three databases for the full round-trip. If each service call averages 40 ms and there are three sequential phases, locks are held ~120 ms per order. At 2,000 QPS that's ~240 concurrent locked transactions in flight (Little's law: 2,000/s × 0.12 s) — and hot rows (popular SKUs, the coordinator's own table) concentrate that contention on a few shards regardless of how evenly you partition. Lock contention collapses throughput long before the CPUs are busy, and a coordinator crash leaves rows locked until timeout.

With an orchestrated saga, each local transaction commits in ~15 ms and releases its locks immediately; the orchestrator carries the state between steps. No cross-service locks exist. The trade you accept: for the brief window (tens to hundreds of ms, sometimes seconds if a service is slow) between the payment authorization hold and the stock reservation, the system is in an inconsistent-but-visible state — funds are held but stock isn't confirmed. When stock reservation fails, the orchestrator fires C2 refund and C1 cancel order. The customer briefly saw a pending authorization, then a refund — eventual consistency, not atomic consistency.

Trade-offs: when to use, when not

Use a saga when a business operation spans multiple services (each with its own database), the steps are long-lived or high-throughput, and the domain tolerates eventual consistency with compensations. This describes most microservice workflows: order fulfillment, travel booking (flight + hotel + car), account provisioning, money transfers between ledgers.

Prefer alternatives when:

Choreography vs orchestration: choreography suits 2–3 steps with simple flow; beyond that, cyclic event dependencies become impossible to trace. Orchestration scales to complex, branching workflows and is usually the senior-interview default for anything non-trivial.

Pitfalls an interviewer probes

Worked choreography example: Order → Payment → Inventory → Shipping

Each service owns its own database and listens to events on a message bus. The happy path looks like this:

StepServiceLocal actionEvent published
T1OrdersCreate order status=PENDINGOrderCreated(orderId=42)
T2PaymentsReserve $50; create chargeId=p-99PaymentReserved(orderId=42, chargeId=p-99)
T3InventoryReserve SKU-7; decrement available stockInventoryReserved(orderId=42, sku=SKU-7)
T4ShippingCreate shipment label; set order status=SHIPPEDOrderShipped(orderId=42)

Each commit is independent. If every step succeeds, the order ends up shipped and no compensations run.

Compensation trace: Payment reserved, Inventory fails

Suppose the inventory service finds SKU-7 is out of stock. It cannot complete T3, so it publishes InventoryReservationFailed. Every service that already completed a step now runs its compensating transaction in reverse order:

CompensationServiceSemantic undoResulting state
C2PaymentsRefund charge p-99; emit PaymentRefundedCustomer sees no charge
C1OrdersCancel order 42; set status=CANCELLEDOrder record closed with reason

Notice inventory does not need a compensation because it never changed state. The saga unwinds only the steps that actually happened. The customer briefly saw a pending authorization, then a refund. Note the ordering choice hiding here: because T2 was an authorization hold rather than a capture, the compensation is a cheap void. A later lesson (The Saga Pattern: A Solution) makes this precise — the irreversible money movement (the pivot) belongs after every step that can still fail, which is why well-designed sagas reserve before they capture.

Choreography vs orchestration decision table

DimensionChoreographyOrchestration
Workflow visibilityScattered across services; hard to traceCentralized in orchestrator; easy to inspect
Adding a new stepTouch every subscriber; risk of event cyclesAdd a command + handler in orchestrator
CouplingLoose temporal coupling, tight semantic coupling via event schemaServices depend on orchestrator commands
Failure recoveryEach service must infer and run compensationsOrchestrator drives compensation order
Best fit2–3 steps, simple flows, event-native architectureComplex, branching, long-lived workflows
ObservabilityNeeds correlation IDs and distributed tracingSaga state is one database query away

Pitfall: the compensating refund race

A subtle trap: what if the refund service is down when the compensation tries to run? Without durable saga state and retries, the order stays paid-but-cancelled. Good saga implementations persist the saga state, retry compensations with exponential backoff, and alert if a compensation is stuck beyond a bounded time.

Key takeaways


Re-authored and deepened for this guide. Sources: Hector Garcia-Molina & Kenneth Salem, "Sagas" (ACM SIGMOD, 1987); Chris Richardson, Microservices Patterns (Manning, 2018), ch. 4 and microservices.io — saga pattern, choreography vs orchestration; Martin Kleppmann, Designing Data-Intensive Applications (O'Reilly, 2017) — 2PC and the blocking problem.

🤖 Don't fully get this? Learn it with Claude

Stuck on Introduction to Saga Pattern? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Introduction to Saga Pattern** (System Design) and want to truly understand it. Explain Introduction to Saga Pattern from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Introduction to Saga Pattern** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Introduction to Saga Pattern** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Introduction to Saga Pattern** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes