is why it's so sneaky: it passes every test on your laptop, then explodes on busy
days.
The fix: don't let them both reach at once
You make the "check and update" happen as one locked step, so the second
request has to wait its turn.
-- Let the database do the check-and-subtract atomically, one at a time
UPDATE products
SET stock = stock - 1
WHERE id = 7 AND stock > 0; -- only succeeds if stock is still > 0
-- if 0 rows changed, you know you were too late. don't ship.
Now the database hands out the cookie to exactly one winner. The loser is told
"sorry, sold out," instead of both walking away thinking they won.
A real case
Race conditions love:
- Selling the last ticket or item.
- Two clicks creating two accounts with the same email.
- A counter (likes, views) losing updates when many people act at once.
The pattern is always the same: read, decide, write, with someone sneaking in
between your read and your write.
Gotchas juniors hit
1. "It works on my machine."
Of course it does. You're the only user. Races need traffic. Test with the real
world in mind.
2. Adding a sleep to "fix" it.
Slowing things down just hides the bug for a while. The race is still there.
3. Trusting a read you made a moment ago.
By the time you write, the value may have changed. Let the database check the
condition at write time.
Recap
- A race condition = the answer depends on who gets there first.
- It hides during quiet times and bites under load.
- The shape is always read, decide, write with a gap in the middle.
- Fix it by making the check-and-change one locked, atomic step.
Your turn
Find a "read, check, then write" in your code (like "if username is free, create
it"). Imagine two users doing it at the exact same millisecond. Could both win?
If yes, you found a race. Tell a friend about the last cookie.