Prepare and commit phases, the blocking problem when participants hold locks awaiting the coordinator, the coordinator single-point-of-failure, and why 2PC doesn't scale across independently-deployed services.
Published September 23, 2026
The classic distributed-transaction protocol — worth understanding precisely specifically because its well-known weaknesses are the reason Saga Pattern and the Outbox Pattern exist as alternatives.
Coordinator → Participant A: "Can you commit this transaction?"
Coordinator → Participant B: "Can you commit this transaction?"
Participant A → Coordinator: VOTE YES (locks resources, writes to a durable log, ready to commit)
Participant B → Coordinator: VOTE YES
Every participant does everything needed to guarantee it can commit if told to — acquiring locks, validating constraints, writing an intent to durable storage — without actually committing yet. Each votes yes (ready) or no (cannot proceed).
// If ALL participants voted YES:
Coordinator → Participant A: COMMIT
Coordinator → Participant B: COMMIT
// If ANY participant voted NO:
Coordinator → Participant A: ABORT
Coordinator → Participant B: ABORT
Only after collecting votes from every participant does the coordinator decide: all-yes means tell everyone to commit; any single no means tell everyone to abort. This gives genuine atomicity across multiple independent systems — either all participants commit, or none do.
Between voting YES and receiving the coordinator's final decision, a participant must hold its locks — it's already promised it can commit, so it can't safely release resources or let other transactions proceed until it knows the final outcome. If the coordinator is slow, or the network between coordinator and participant is disrupted, that participant sits blocked, holding locks, potentially for a long time — other transactions waiting on those same locked resources are blocked transitively too.
If the coordinator crashes after collecting all votes but before every participant receives the final decision, participants that voted YES are stuck — they can't unilaterally decide to commit or abort (they don't know what the other participants voted, or what the coordinator ultimately decided), so they remain blocked indefinitely, holding locks, until the coordinator recovers and completes the protocol. This is 2PC's most cited weakness: a coordinator failure at exactly the wrong moment can leave the entire system stuck.
Beyond the blocking problem, 2PC assumes participants are cooperatively coordinated — they trust a shared coordinator, tolerate holding locks for however long the protocol takes, and are typically within the same administrative/network domain (classically, multiple databases under one DBA's control). Independently-deployed microservices violate nearly every one of these assumptions: each service is deployed and scaled independently, network partitions between services are a normal operating condition (not a rare edge case), and a service holding locks indefinitely while waiting on a coordinator directly contradicts the availability and independent-scalability goals microservices are built for in the first place. This is precisely why Saga Pattern (accepting eventual consistency in exchange for availability and loose coupling) is the standard alternative in a microservices context, not 2PC.
Q: Is 2PC ever still the right choice in a modern system? A: Yes, within a bounded, cooperatively-controlled scope — a single database's own internal distributed transaction across its own shards/replicas, or a small number of tightly-coupled, co-located systems under unified operational control, where the blocking risk is acceptable and strong atomicity genuinely matters more than availability.
Q: How does 2PC's 'prepare' phase relate to a database's own write-ahead log (see ACID Properties)? A: Conceptually similar — both are about durably recording an intent BEFORE the final, irreversible action, so a crash mid-process can be recovered from correctly by consulting the durable log/prepare-state rather than being left in an ambiguous state.
Q: What's Three-Phase Commit, and does it solve the blocking problem? A: 3PC adds an extra phase specifically to reduce (not eliminate) the blocking window by giving participants more information before committing to an irreversible action — it's a real refinement, but adds its own complexity and latency cost, and still doesn't fully solve coordinator-failure scenarios in all cases, which is part of why the industry largely moved toward Saga-style patterns for distributed microservices rather than refining synchronous coordination protocols further.
Q: How would you detect a stuck 2PC transaction in production? A: Monitoring for locks held unusually long (beyond the typical transaction duration for that resource) is the direct symptom — a participant stuck in the prepared-but-not-yet-committed state shows up as an anomalously long-held lock, which ties directly back to Locking Strategies' lock-timeout discussion as a partial mitigation (though a lock timeout on a prepared 2PC transaction risks violating the atomicity guarantee if used carelessly).