I use two phase commit as the example of paying coordination cost for all or nothing behavior. I recommend it only when partial success is worse than slower commits and blocking risk.
Prepare first, commit second
I use this section to force the failure case into the conversation, not just the clean path.
In phase one, the coordinator asks each participant to prepare. A prepared participant records enough information to commit later. In phase two, the coordinator tells everyone to commit or roll back.
Reservation example
I keep the example grounded in production behavior: owner, delay, retry, and recovery.
An order workflow needs inventory and payment to succeed together. If payment prepares but inventory cannot prepare, the coordinator rolls the transaction back.
Coordinator code
I use the code here to show the decision boundary, not just syntax.
Prepare every participant before sending the final commit:
if (payment.prepare(xid) && inventory.prepare(xid)) {
payment.commit(xid);
inventory.commit(xid);
} else {
payment.rollback(xid);
inventory.rollback(xid);
}
The coordinator commits only when both participants prepare successfully. If either side cannot prepare, both roll back so the transaction does not split.
Sequence diagram: prepare before commit
The final commit only happens after every participant promises it can finish.
The atomicity choice
- Use it when partial success is more expensive than coordination.
- Plan for coordinator failure and participant recovery.
- Avoid it for high volume loose workflows where events and compensation are enough.