ediverse Explore the platform

Spotlight PEPPOL BIS Billing 3.0 The EU e-invoicing mandate is here — France Sept 2026, Belgium Jan 2026, Germany 2025.

Two-Phase Commit (2PC)

How to guarantee that a transaction is committed everywhere or nowhere when it spans N independent nodes — at the price of possible blocking if the coordinator fails.

Problem

A business transaction must atomically modify several distinct resources (for example debit a supplier account and credit a logistics account in two different RDBMS, or simultaneously validate a received AS4 message and enqueue an APERAK). Without coordination, one may commit and the other fail, leaving the system in an inconsistent state. The ACID Atomicity property must hold across each resource boundary.

Forces

  • Latency: 2PC adds two network round-trips on the critical path (prepare + commit).
  • Blocking: if the coordinator dies between prepare and commit, participants remain in prepared state (locks held) until coordinator recovery or human intervention.
  • Failure detection: 2PC assumes a fail-stop environment; Byzantine failures are not addressed.
  • Strong temporal coupling: all participants must be available simultaneously during prepare.
  • Standardisation: XA/Open Group (1991) and JTA (J2EE) standardised the APIs; implementations diverge significantly.

Solution

The coordinator orchestrates two distinct phases. Phase 1 (prepare): the coordinator sends PREPARE to each participant; each one performs all checks, writes its redo/undo log and answers VOTE-COMMIT ("I can") or VOTE-ABORT ("no"). Phase 2 (commit/abort): if all vote COMMIT, the coordinator writes COMMIT to its log and sends COMMIT to all; otherwise it sends ABORT. Participants ack and release locks. Phase 1 preserves participant log durability; phase 2 guarantees global atomicity.

Structure

              ┌─────────── Coordinator ───────────┐
              │                                    │
              │ Phase 1: PREPARE                   │
              │ ─────────► Participant A           │
              │ ─────────► Participant B           │
              │ ─────────► Participant C           │
              │                                    │
              │ ◄──────── VOTE-COMMIT (A)         │
              │ ◄──────── VOTE-COMMIT (B)         │
              │ ◄──────── VOTE-COMMIT (C)         │
              │                                    │
              │ [WRITE "commit" in log] ★ DURABLE │
              │                                    │
              │ Phase 2: COMMIT                    │
              │ ─────────► A, B, C                 │
              │ ◄──────── ACK from all             │
              └────────────────────────────────────┘

If any VOTE-ABORT:
  Coordinator writes "abort", broadcasts ABORT → participants rollback.

If coordinator crashes after ★:
  All participants stay BLOCKED (locks held)
  until coordinator recovery reads log and resends COMMIT/ABORT.

EDI implementation

In 2026, 2PC has almost no place in a modern EDI hub — it is unsuited to multi-partner asynchronous flows where each party has its own tempo. One residual case remains: atomic update between a message database (PostgreSQL) and a persistent queue (RabbitMQ with XA extension, IBM MQ) inside a single hub. In practice the Outbox pattern has almost always replaced this need. When a hub must interact with a transactional ERP (SAP NetWeaver via JCA) that supports XA, 2PC remains an option to guarantee that the ingested EDIFACT message and the SAP table insertion commit together. The practical rule: if the partner is external (AS2, AS4, OFTP2), never enrol the partner in an XA transaction — use a saga.

Anti-patterns

  • Extending 2PC to an external partner over the Internet — the slightest latency or network failure blocks the transaction for a long time.
  • Single coordinator without HA — its crash halts every flow until manual recovery.
  • Mixing XA and non-XA resources in the same transaction — the ACID guarantee is now only partial (and it is worse than nothing).
  • Confusing 2PC and Saga — 2PC locks, Saga compensates; they are not alternatives to the same problem.
  • Marketing 2PC as "transparent to the developer" — XA deadlock analysis remains one of the most complex topics in back-end engineering.
  • Three-Phase Commit (3PC) — non-blocking variant at the cost of an extra round-trip and stronger synchrony assumptions.
  • Saga (orchestration) — recommended alternative for long EDI flows where blocking is not acceptable.
  • Transactional Outbox — supplants 2PC in the local DB+queue case by publishing events from the same local transaction.
  • Consensus (Raft) — modern distributed consensus variant adopted by etcd, CockroachDB.

Sources

  • Gray J. — Notes on Database Operating Systems, IBM Research RJ2188, 1978. The foundational paper where 2PC is first described. jimgray.azurewebsites.net
  • X/Open Distributed Transaction Processing — The XA Specification, X/Open CAE Specification, 1991. The standardisation of 2PC that structured JTA, MS DTC, Tuxedo.
  • Bernstein P., Hadzilacos V., Goodman N. — Concurrency Control and Recovery in Database Systems, Addison-Wesley, 1987, ch. 7.
  • Kleppmann M. — Designing Data-Intensive Applications, O'Reilly 2017, ch. 9 ("Distributed transactions and 2PC").
  • Pat Helland — Life Beyond Distributed Transactions: An Apostate's Opinion, ACM Queue 2007, explaining why 2PC does not scale.