Mock a Two-Phase Commit Coordinator in Python
Simulates a two-phase commit protocol where a coordinator asks participants to prepare, then commits or aborts based on unanimous readiness.
Python code
39 linesimport random
import time
from typing import Dict, List
class TwoPhaseCommitCoordinator:
def __init__(self, participants: List[str]):
self.participants = participants
self.participant_state: Dict[str, bool] = {}
def prepare(self) -> bool:
print("[Coordinator] Phase 1: Prepare")
for participant in self.participants:
decision = random.choice([True, False])
self.participant_state[participant] = decision
print(f" {participant} -> {'ready' if decision else 'abort'}")
time.sleep(0.1)
return all(self.participant_state.values())
def commit(self):
print("[Coordinator] Phase 2: Commit")
for participant in self.participants:
print(f" {participant} -> committed")
def abort(self):
print("[Coordinator] Phase 2: Abort")
for participant in self.participants:
print(f" {participant} -> rolled back")
def run(self):
if self.prepare():
self.commit()
else:
self.abort()
if __name__ == "__main__":
coordinator = TwoPhaseCommitCoordinator(["db_a", "db_b", "db_c"])
coordinator.run()
Output
[Coordinator] Phase 1: Prepare
db_a -> ready
db_b -> ready
db_c -> abort
[Coordinator] Phase 2: Abort
db_a -> rolled back
db_b -> rolled back
db_c -> rolled back
How it works
This mock demonstrates the core safety of two-phase commit: no participant finalizes until every participant confirms it can prepare. The coordinator tracks each participant's vote in participant_state and only proceeds to commit if all votes are true; any abort cascades to a rollback everywhere. The random.choice simulates real-world uncertainty like network timeouts or disk failures. This pattern ensures atomicity across distributed systems without relying on a single shared lock.
Common mistakes
- Committing when only some participants voted ready — must require all votes true
- Forgetting to roll back every participant on abort to avoid partial writes
- Ignoring timeouts or retries when a participant never responds in production
Variations
- Add a recovery log to replay prepare/commit decisions after a crash
- Use explicit timeouts with retry loops instead of random success flags
Real-world use cases
- Simulating a cross-database transaction where all shards must commit atomically.
- Teaching or prototyping distributed consensus before implementing with real RPCs.
- Testing failure scenarios in a saga or microservices rollout where partial commits are dangerous.
Sponsored
More from Reliability & rate limiting
- At Least Once with Idempotent Consumer in Python medium
- Build a Rate Limiter Decorator in Python easy
- Build a queue-based admission control system in Python easy
- Chaos Inject Random Failures in Python easy
- Circuit breaker failure threshold count in Python medium
- Exactly Once Processing Dedupe Mock in Python easy
Keep learning
Related tutorials and quizzes for this topic.