Menu

Earn Premium with Referrals

Invite your friends and earn Premium rewards through our referral program.

See how it works and start inviting friends.

Distributed Transactions
HLD

Distributed Transactions

Atomicity across services — why 2PC loses, what sagas win with, and where each still fits.

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

FlowApproachWhy
Checkout (order+stock+pay)saga, orchestratedmulti-service truth
Profile updateplain local txnsingle owner!
Bank transfer inside one ledger DBlocal ACIDco-located by design
Rare admin bulk ops2PC tolerablevolume 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.

My Private Notes

Notes are auto-saved locally to this device.