The Cross-Service Atomicity Problem
place-order touches three services' databases:
[orders-db] create order
[inventory-db] reserve stock ← all-or-nothing?
[payments-db] capture funds
local ACID covers ONE database. across three:
partial completion = phantom orders, ghost reservations,
captured money for nothing.
distributed-transaction options, honestly priced:
2PC/XA: locks span services; blocking on coordinator death;
throughput collapses; many stores don't support it.
VIABLE only for low-volume internal coordination.
Sagas: The Microservices Answer
sequence of LOCAL transactions + compensating actions:
OrderSaga (choreographed or orchestrated):
1. orders.create(PENDING) ✓ local txn
2. inventory.reserve ✓
3. payments.capture ✓ → orders.confirm()
any step fails → run compensations in reverse:
inventory.release / orders.cancel
TWO coordination styles:
CHOREOGRAPHY: services react to events; no conductor.
+ loose coupling − flow invisible; branching hard
ORCHESTRATOR: central saga state machine drives steps.
+ visible/recoverable flows − one more component owning logic
large estates usually end up orchestrating complex sagas,
choreographing simple ones.
The Semantic Shift That Makes Sagas Safe
sagas are NOT ACID — design for their reality:
□ INTERMEDIATE STATES ARE VISIBLE:
order shows PENDING while payment runs. UX must speak it
("confirming your order...") — hiding it lies.
□ COMPENSATIONS ≠ ROLLBACK:
released stock may already be sold elsewhere;
compensated charge is a REFUND (visible, real-world).
compensations are business actions, not undo-magic —
and can THEMSELVES fail → retry/alert paths needed.
□ IDEMPOTENCY EVERYWHERE: retries at every step guaranteed.
□ COUNTERMEASURES for the classic gaps:
LOST UPDATE: per-entity serialization (own lesson)
DIRTY READS: version/status checks before acting
Fuzzy results: semantic locks (PENDING states block rivals)
Choosing Per Flow
| Flow | Approach | Why |
|---|---|---|
| Checkout (order+stock+pay) | saga, orchestrated | multi-service truth |
| Profile update | plain local txn | single owner! |
| Bank transfer inside one ledger DB | local ACID | co-located by design |
| Rare admin bulk ops | 2PC tolerable | volume tiny |
the senior reflex remains: FIRST ask whether data-model
redesign makes it LOCAL (co-location, database-per-
service done right). distributed transactions should be
a last resort, chosen knowingly — not the default shape
of every feature.
Interview Framing
“Order placement must atomically update orders, inventory, and payments” scored shape: reject naive cross-service txn immediately, saga designed WITH compensation examples that acknowledge real-world effects (refunds!), orchestration-vs-choreography choice justified, intermediate-state UX honesty named, idempotency assumed aloud, local-first redesign question asked first. Distributed-transaction questions grade whether you treat atomicity as a DESIGN input rather than an infrastructure feature to wish for.
Premium Content
Unlock Distributed Transactions and all premium lessons with a subscription.
All premium lessons
Ad-free experience
Priority support
From ₹199.99/year — See plans