How to Implement Read-After-Write Consistency Mock in Python
Simulate strong versus eventual read-after-write consistency with a primary and replica store, demonstrating the difference in data visibility over time.
Python code
42 linesimport time
class MockStorage:
def __init__(self, write_delay=0.1):
self.store = {}
self.replica = {}
self.write_delay = write_delay
def write(self, key, value):
# Write to primary storage immediately
self.store[key] = value
# Simulate async replication delay
time.sleep(self.write_delay)
# The write is now visible to reads
self.replica[key] = value
def read(self, key, strong_consistency=True):
if strong_consistency:
# Strong consistency: read from primary
return self.store.get(key)
else:
# Eventual consistency: read from replica
return self.replica.get(key)
if __name__ == "__main__":
storage = MockStorage(write_delay=0.2)
# Initial state
print(f"Before write - eventual read: {storage.read('game_score', strong_consistency=False)}")
# Write a value
storage.write("game_score", 1500)
# Immediately after write (but before replication delay)
print(f"After write - strong read: {storage.read('game_score', strong_consistency=True)}")
print(f"After write - eventual read (before replication): {storage.read('game_score', strong_consistency=False)}")
# Wait for replication to complete
time.sleep(0.1)
print(f"After delay - eventual read: {storage.read('game_score', strong_consistency=False)}")
Output
Before write - eventual read: None
After write - strong read: 1500
After write - eventual read (before replication): None
After delay - eventual read: 1500
How it works
The MockStorage class models a simple database system with a primary store and an async replication delay. When write() is called, it writes to the primary immediately, then sleeps to simulate replication lag before updating the replica. The read() method offers two consistency levels: strong reads always hit the primary store, guaranteeing the latest value, while eventual reads hit the replica, which may lag briefly. This pattern demonstrates why strongly-consistent reads are safer for critical data but cost more in latency, while eventual consistency gives faster reads at the risk of seeing stale data. The timing in __main__ shows the window where strong and eventual reads disagree before replication finishes.
Common mistakes
- Forgetting that `time.sleep` in write blocks the caller instead of truly replicating asynchronously in real systems
- Using eventual reads for critical operations like order confirmation or balance checks
- Not accounting for replication lag when testing data-dependent logic
Variations
- Use a separate thread or a queue to simulate truly asynchronous replication without blocking the writer
- Add a `replication_lag` counter or simulate out-of-order replication for more realistic behavior
Real-world use cases
- Unit-testing application code that must behave correctly when reads see stale replicas after a write.
- Demonstrating consistency models to teammates when designing a feature that reads user-profile updates.
- Validating a caching layer's invalidation strategy where eventual consistency is acceptable for non-critical reads.
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.