Race Conditions & Lost Updates
The core problem
A race condition occurs when the correctness of a result depends on the unpredictable interleaving of concurrent operations. The classic failure mode is the lost update: two clients read the same value, each computes a new value from the stale copy, and one write silently overwrites the other.
Read-modify-write is the danger zone
Consider an inventory counter at stock = 10. Two requests both want to decrement it:
- Request A reads
10, computes9. - Request B reads
10(before A writes), computes9. - A writes
9. B writes9.
Two units were sold but stock only dropped by one — the update from one request was lost. The same pattern corrupts wallet balances, like counts, seat reservations, and any aggregate that is read, modified in application code, then written back.
Two families of solutions
You can either detect the conflict and retry (optimistic concurrency), or prevent the interleaving by serializing access (pessimistic locking). Atomic primitives such as a single-statement UPDATE ... SET stock = stock - 1 or a compare-and-swap sidestep the read-modify-write window entirely and should always be your first choice when the operation can be expressed atomically.
The window between one client's read and its write is exactly where another writer sneaks in and clobbers the result.
Both solution families close this window — one by detecting that the value changed, the other by blocking the second writer until the first is done.