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.

Medium Python 3.9+ Aug 9, 2026 Reliability & rate limiting 12 views 0 copies

Python code

39 lines
Python 3.9+
import 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

stdout
[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

  1. Add a recovery log to replay prepare/commit decisions after a crash
  2. 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

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Reliability & rate limiting

Related tutorials and quizzes for this topic.