Playbook

Why Eventual Consistency Beats Distributed Transactions (Why Eventual Consistency Beats Distributed Transactions)

Building a 2PC across the PSP, the order, and finance is a trap. Saga plus reconciliation is the real answer this eight-part arc has been building toward.

Distributed Payment Engine

Part 16 of 22

A series on distributed payment architecture — the gap between capture and complete.

Distributed payment engine architecture diagram

Across these eight parts we moved from provider abstraction to semantic events, failure taxonomy, retry algorithms, leases, reconciliation, and healing orphan charges. The question underneath all of it can finally be asked directly: why endure all this complexity? Why not just wrap the PSP, the order, and the finance record in one transaction and solve every one of these problems at once?

The answer is simple and final: the PSP can never participate in your transaction.

What 2PC requires
  Coordinator ←→ Participant 1 (Order DB)
  Coordinator ←→ Participant 2 (Finance DB)
  Coordinator ←→ Participant 3 (PSP??)

The PSP's actual world
  Doesn't run your transaction protocol
  Lives on its own network boundary, with its own consistency model
  Has no concept of your 'prepare' or 'commit' signal

Where the concepts first show up

📦 Two-Phase Commit (2PC)
A protocol that gets multiple participants to either fully commit or fully roll back a transaction together.

📦 Saga
A pattern that splits a workflow that doesn't fit in a single ACID transaction into a sequence of local operations, each with its own compensation.

📦 Eventual consistency
A model that accepts the system may not be consistent at every instant, but converges to a consistent state within a bounded time.

📦 Reconciliation as backstop
The final safety net that restores the true state when a saga's compensation step fails or gets skipped.

2PC requires every participant to share the same coordinator, the same protocol, and the same assumptions about network reliability. The PSP accepts none of that — it's a system outside your control, running on its own SLA, its own API, and its own failure model.

Why the PSP can't join a 2PC

Even if you wanted to send a PSP a 'prepare' request followed by a 'commit' or 'rollback', it wouldn't support that two-phase protocol — because the card itself, the bank network, and fraud checks already made their decision, usually in a single phase. A PSP's API doesn't say 'I'll decide later, wait'; it says 'yes' or 'no'. If the second phase (commit) fails on your side, there's no concept of the PSP rolling back its operation — there's only a separate refund request, which is itself an asynchronous, unguaranteed operation.

The world 2PC assumes
  Prepare → every participant says 'ready' → Commit → all accept at once

The PSP's real world
  Charge request → the PSP decides instantly → the outcome is final
  Want to undo it → a separate Refund request, a separate async process

Saga: a chain of local decisions

The approach that replaces 2PC has each system run its own local transaction, moving to the next step only via an event. If a step fails, prior steps aren't rolled back — each is corrected by its own compensating action.

Charge succeeds at the PSP
  → create the order (local transaction)
  → create the finance record (local transaction)

If the finance record fails
  → compensation for the order: cancel it
  → compensation for the PSP: send a refund request

This is the direct consequence of the 'capture is easy, finalization is hard' fact from earlier in this series: the difficulty of finalization is exactly the difficulty of designing a saga's compensating steps.

Reconciliation: the saga's safety net

A saga doesn't guarantee its compensating steps always run — the compensation request can fail too, the network can drop, a worker can crash. That's exactly why everything built in the previous parts (leases, the reconciliation worker, orphan-charge healing) is the second layer that cleans up the moments a saga alone isn't enough.

Saga (the primary path)
  → moves step by step, each step owning its own compensation

Reconciliation (the secondary safety net)
  → periodically scans for and corrects what the saga skipped or failed to compensate

The real cost of eventual consistency: a window, not incorrectness

Eventual consistency doesn't mean 'the data can be wrong for a while'; it means 'the data can be incomplete or stale for a while, but that while is measured and bounded'. That window needs to be visible on the product side: how many seconds or minutes can pass before an order's status is visible after payment? That's not a technical detail, it's a product decision — and it's the core of what this series has argued from the start: in a distributed payment system, perfect instantaneous consistency is an illusion; the real goal is a short, measured, observable window of inconsistency.

Approach Guarantee Actually achievable
2PC (including the PSP) Instant, full consistency No — the PSP can't participate
Saga + compensation Step-by-step progress, retroactive correction Yes
Saga + reconciliation A bounded, measured inconsistency window Yes — the model this series has argued for

Distinctions that get blurred

❌ Eventual consistency = an inconsistent system
✓ Eventual consistency = converging to consistency within a bounded, measured window

❌ A saga is just a simpler version of 2PC
✓ A saga is a different model entirely: there's no rollback, only compensation

❌ Needing reconciliation means the saga was designed badly
✓ Reconciliation is a permanent safety net inherent to distributed systems, not a saga's shortcoming

2PC vs. Saga + Reconciliation

Criterion 2PC Saga + Reconciliation
PSP participation Required but impossible Not required
Lock duration Held across all participants None
Resilience to partial failure Low High
Operational complexity Low in theory, impossible in practice High but real

Checklist for evaluating this model

  1. Can every external dependency in the system (including the PSP) join the same transaction protocol? If not, 2PC isn't an option.
  2. Does every saga step have a clearly defined compensating action?
  3. What happens when a compensating action fails — does it silently disappear, or does reconciliation catch it?
  4. Is the eventual-consistency window measured and shared with the product team?
  5. Does the system target 'consistent within a short bounded time' rather than the illusion of 'consistent at every instant'?

What to take away from these eight parts

  1. The PSP is an external system and can never join your transaction protocol — that's exactly why 2PC is a trap.
  2. A saga is the realistic alternative, where every step runs its own local transaction and owns its own compensation.
  3. Reconciliation isn't a saga's shortcoming; it's a permanent safety net inherent to distributed systems.
  4. Eventual consistency isn't incorrectness — it's a measured, observable window of convergence.

What a distributed payment system needs isn't perfect instantaneous consistency — it's knowing precisely how long the inconsistency will last.

This closes the eight-part arc that started with provider abstraction: keeping SDKs from leaking, producing semantic events, classifying failure correctly, retrying with discipline, safely owning work with leases, catching drift through reconciliation, and healing orphan charges with evidence — all of it serves one single fact: a distributed payment system doesn't aim for perfection, it aims for controlled, observable inconsistency.

FAQ

Frequently asked questions

What is Two-Phase Commit (2PC)?

A protocol that gets multiple participants to either fully commit or fully roll back a transaction together.

What is Saga?

A pattern that splits a workflow that doesn't fit in a single ACID transaction into a sequence of local operations, each with its own compensation.

Is it true that "Eventual consistency = an inconsistent system"?

Eventual consistency = converging to consistency within a bounded, measured window

What does this part lock in?

The PSP's actual world Doesn't run your transaction protocol Lives on its own network boundary, with its own consistency model Has no concept of your 'prepare' or 'commit' signal ``` The PSP is an external system and can never join your transaction protocol — that's exactly why 2PC is a trap. Across these eight parts we moved from provider abstraction to semantic events, failure taxonomy, retry algorithms, leases, reconciliation, and healing orphan charges. The question underneath all of it can finally be asked directly: why endure all this complexity? Why not just wrap the PSP, the order, and the finance record in one transaction and solve every one of these problems at once?

Engineering Principles Learned

  • The PSP can never join your transaction protocol — that's why 2PC is a trap.
  • A saga doesn't roll back, it compensates — a genuinely different model.
  • Eventual consistency isn't incorrectness, it's a measured, observable window.

Continue reading

Continue reading

Next in series

Next in series

Same series

Paylaş