Two Phase Commit Cross Shard Mock in Python
Simulates a two-phase commit across shards with failure handling to demonstrate distributed transaction coordination in Python.
Python code
61 lines"""Mock cross-shard two-phase commit with caution handling."""
class Shard:
def __init__(self, name):
self.name = name
self.prepared = False
self.committed = False
self.aborted = False
def prepare(self):
# Simulate potential failure (1 in 3 chance on third shard)
if self.name == "shard3" and not self.prepared:
print(f" {self.name}: prepare FAILED")
self.aborted = True
return False
self.prepared = True
print(f" {self.name}: prepared")
return True
def commit(self):
self.committed = True
print(f" {self.name}: committed")
def abort(self):
self.aborted = True
print(f" {self.name}: aborted")
class TransactionCoordinator:
def __init__(self, shards):
self.shards = shards
def run(self):
print("Phase 1: Prepare")
all_prepared = True
for shard in self.shards:
# Simulate independent preparation attempt
if shard.prepare():
continue
all_prepared = False
# Caution: abort already-prepared shards
print("Caution: abort initiated - shard failed to prepare")
break
if all_prepared:
print("Phase 2: Commit")
for shard in self.shards:
shard.commit()
else:
print("Phase 2: Abort (rollback)")
for shard in self.shards:
if shard.prepared and not shard.aborted:
shard.abort()
elif shard.aborted:
print(f" {shard.name}: already aborted")
if __name__ == "__main__":
shards = [Shard("shard1"), Shard("shard2"), Shard("shard3")]
coordinator = TransactionCoordinator(shards)
coordinator.run()
Output
Phase 1: Prepare
shard1: prepared
shard2: prepared
shard3: prepare FAILED
Caution: abort initiated - shard failed to prepare
Phase 2: Abort (rollback)
shard1: aborted
shard2: aborted
shard3: already aborted
How it works
This simulation models a two-phase commit protocol where a coordinator first asks each shard to prepare, then either commits all or aborts all. The Shard class tracks state per shard (prepared, committed, aborted) to simulate real distributed behavior. The coordinator stops preparing further shards once one fails, then rolls back any that already prepared. Running the script may produce different output than shown because the failure on shard3 is deterministic here; in real systems, prepare calls can fail independently and the coordinator must handle partial preparation. This pattern is a simplification but shows the core logic behind distributed transaction coordinators.
Common mistakes
- Assuming all shards prepare successfully without checking return values
- Forgetting to abort already-prepared shards when one fails
- Not tracking each shard's state independently
- Ignoring the chance of network errors during commit phase
Variations
- Use a database like PostgreSQL with two-phase commit support (e.g., `PREPARE TRANSACTION`)
- Implement the coordinator using `concurrent.futures` to prepare shards in parallel
Real-world use cases
- Coordinating writes across multiple database shards in a distributed system to maintain consistency.
- Simulating a two-phase commit for testing transaction handling in a microservices architecture.
- Applying the prepare/commit/abort pattern to resource allocation across distributed services, like reserving seats across multiple inventory systems.
Sponsored
More from Database scaling & optimization
- Approximate Count with HyperLogLog in Python medium
- B-Tree Insert and In-Order Traversal in Python hard
- Broadcast a Small Reference Table in Python easy
- Build a Full Text Search Index in Python medium
- Build a Partial Index Mock in Python for Database Filtering easy
- Composite index leftmost prefix in Python medium
Keep learning
Related tutorials and quizzes for this topic.