Atomicity across services you do not control

Distributed Transactions & Sagas

7 lessons. Every one names the guarantee it claims, what a node can know, and how it fails.

Atomicity Stops at the Process Boundary▶ lab

One database gives you all-or-nothing for free. Two services do not, because there is no component that can see both uncommitted states at once. Before reaching for a protocol, look hard at whether the invariant has to span the boundary at all.

Q · Two services must both change state, or neither. Neither can see the other’s uncommitted work. What are my actual options?

Two-Phase Commit: Buying Atomicity With a Promise▶ lab

2PC makes several independent stores commit or abort together. It works by making each participant give up its right to decide alone — and that surrendered right is both the source of the guarantee and the source of every problem the protocol has.

Q · How can three independent databases be made to commit or abort as one, and what exactly does that cost?

The Blocking Window: When 2PC Stops and Waits▶ lab

The real objection to two-phase commit is one specific gap: the coordinator dies after collecting YES votes, and every participant sits holding locks with no legal way to decide. Understanding that window precisely tells you both why 2PC gets a bad name and how modern systems remove the problem.

Q · The coordinator crashed after everyone voted yes. Why can the participants not simply decide for themselves?

Sagas: Trading Isolation for Availability▶ lab

A saga replaces one atomic transaction with a sequence of local ones, each committed immediately and each paired with a compensating action. It never blocks. In exchange it gives up the "I" in ACID entirely — the half-finished state is visible to everyone, and your business logic now has to cope with it.

Q · If I cannot hold a transaction open across services, what does the alternative actually guarantee — and what does it stop guaranteeing?

A Refund Is Not a Rollback▶ lab

A rollback erases history: the old value returns and nobody can prove the new one ever existed. A compensation adds history: the money moved, then moved back, and the statement shows both lines. Time did not reverse. Everything hard about sagas follows from that one difference.

Q · My saga failed at step 3, so I will undo steps 1 and 2. Why is "undo" the wrong word, and what does it cost me to use it?

Orchestration: One Component Owns the Workflow▶ lab

An orchestrator holds the saga as an explicit state machine, issues commands and records replies. You can point at one place and ask "where is order 4821?" — and you have created a component that every workflow now depends on, and whose deployments must cope with thousands of in-flight sagas running the previous version.

Q · Who owns the knowledge of what step a saga is on — and what changes when the answer is "one component"?

Choreography: The Workflow Nobody Wrote Down▶ lab

Each service reacts to events and publishes its own. No component owns the flow, so adding a participant requires changing nothing upstream. The cost is that the workflow exists only as an emergent property of a subscription graph — and nobody can read it, test it end to end, or say where a given order is.

Q · If services just react to each other’s events, what happens to the workflow — and to my ability to reason about it?