Eventual Consistency: Handling Race Conditions in Event-Driven Systems
Fast recall
Quick revision
Core answer
Whether you understand the practical consequences of eventual consistency and have strategies for handling them in user-facing applications
Assuming eventual consistency is always fine for users — without compensating UX or technical patterns, users see confusing inconsistent states
Discuss the read-your-own-writes problem specifically, explain optimistic locking with version numbers, and give a concrete UX strategy (pessimistic locking vs optimistic UI)
Interview-ready guide
Interview answer
Eventual consistency creates real user-facing problems if you do not design for them explicitly. The most common is read-your-own-writes: a user places an order, gets a success response, navigates to their order list, and the order is not there — the write went to the primary database, but the order list reads from a CQRS projection that has not yet processed the event.
Fixing the read-your-own-writes problem:
- The simplest fix: don't re-query after a write; return the written data directly from the POST response so the user's browser has fresh data without hitting a potentially stale read model
- For operations that take longer, return HTTP
202 Acceptedwith aLocationheader pointing to a status endpoint, letting the client poll until processing completes - Optimistic UI patterns show the expected end state immediately and correct only if the event processing reveals an error
Concurrent modifications:
- Two services updating the same entity simultaneously can cause the "last writer wins" problem where one state transition is silently lost
@Versionoptimistic locking in JPA detects conflicts: if two transactions read version 3 and both try to save version 4, one getsOptimisticLockExceptionand must retry- This is cheaper than pessimistic locking for read-heavy systems and prevents silent data loss from concurrent saga participants
Cache invalidation under async propagation:
- TTL-based expiration doesn't work well with event-driven updates — an event changed state 200ms ago, but the cache TTL is 60 seconds
- The fix is event-driven cache invalidation: subscribe to the same events that update the read model and invalidate relevant cache entries when the event arrives
I recommend the diagnostic rule: if the problem is intermittent and resolves after a few seconds, it's propagation delay; if the problem produces permanently wrong state, it's a concurrent modification issue — they require different fixes.
Eventual Consistency: Handling Race Conditions in Event-Driven Systems
Direct Answer
Eventual consistency means reads may return stale data while events propagate. Handle this with: optimistic locking (version fields) to detect concurrent modifications, idempotent consumers to safely reprocess, read-your-own-writes patterns (read from write-ahead log or cache), and UI patterns that acknowledge async processing rather than showing stale state.
Common Mistakes & Pitfalls
Assuming eventual consistency is always fine for users — without compensating UX or technical patterns, users see confusing inconsistent states
Check your understanding
Answer these without looking back at the article.
- What is the difference between optimistic locking and pessimistic locking in JPA?
- How would you implement a read-your-own-writes guarantee across a distributed read model?
- What is the 'lost update' problem and how does @Version prevent it?
Related interview prep categories
2Want a guided curriculum order?
These modules are also sequenced in our flagship backend interview track — open it when you prefer an ordered path instead of browsing by topic.