Question presented to candidate: "An order has to be written to the orders database, the payments database and the inventory database, and either all three changes happen or none do. Explain how two-phase commit achieves that, walk me through what happens when a participant or the coordinator fails, and tell me why many teams avoid it between microservices."
What a strong answer should cover:
- The goal is atomic commit across separate databases (participants), driven by a coordinator
- Phase 1 (prepare / vote): each participant makes its changes durable, keeps its locks and votes YES or NO; a YES is a promise it can no longer break on its own
- Phase 2 (commit / abort): the coordinator forces its decision to its own log first, then tells everyone; any NO or timeout before the decision means abort
- The core drawback is blocking: a participant that voted YES and lost the coordinator is in doubt and holds its locks until the coordinator recovers
- Cost: two round trips to the slowest participant, extra forced log writes, locks held across the network; heuristic decisions by operators break atomicity
- Alternatives and fixes: replicate the coordinator with consensus (Spanner style), 3PC (not safe under partitions), or avoid distributed transactions with a saga or an outbox
Clarifying questions expected:
- Are all participants databases we control that support a prepare step (XA,
PREPARE TRANSACTION), or are some of them third-party APIs? - How long can the affected rows stay locked, and is temporary unavailability acceptable in exchange for atomicity?
Code / implementation expected: Optional โ a clear walk-through of both phases and the failure cases; the example simulates the protocol on a fake clock.