Race condition

Two things happen at once and the result depends on which one wins. Fine on your laptop, chaos under real traffic.

two people bought the last one at onceit breaks only under loadconcurrency bugworks locally but breaks in proddouble booking bugracing conditiontiming bugtwo requests stepped on each other

See it

Live demo coming soon

What it is

A race condition is a bug where the answer depends on who gets there first. Two requests read 'stock: 1' at the same millisecond, both decide there is enough, and both sell it. The classic shapes are check-then-act (read a value, decide, write) and read-modify-write (fetch a count, add one in your code, save it back), where a second actor slips into the gap between the read and the write and the loser's update vanishes. That vanishing is called a lost update.

The fixes all remove the gap rather than shrink it. Push the decision into the database as one atomic statement (UPDATE inventory SET stock = stock - 1 WHERE id = $1 AND stock > 0, then check rows affected). Lock the row you are about to change with SELECT ... FOR UPDATE inside a transaction. Add a unique constraint so the database refuses the duplicate no matter who wins. Or use optimistic locking: keep a version column and reject the write if the version moved.

The trap is thinking 'I checked first, so it's fine'. Reading before writing is exactly the bug. The second trap is testing: races are non-deterministic, so your test suite passes forever and the bug only appears at 200 requests per second, or the day a queue starts running two workers. Reproduce them on purpose by firing concurrent requests at the same row and asserting the final count.

Ask AI for it

Fix the race condition in [FUNCTION / ENDPOINT], which currently reads a value, decides, and then writes (check-then-act). Replace it with a single atomic database operation: do the guard in the WHERE clause (for example UPDATE inventory SET stock = stock - :qty WHERE id = :id AND stock >= :qty) and treat zero affected rows as the 'not available' case. If the logic spans multiple tables, wrap it in one transaction and lock the target rows with SELECT ... FOR UPDATE in a consistent order to avoid deadlocks, or add a version column and do optimistic locking with a retry on conflict. Back it up with a unique constraint or CHECK constraint so the invariant holds even if new code forgets. Then write a test that runs 50 concurrent calls and asserts the final state is correct exactly once.

You might have meant

database transactiondatabase lockoptimistic lockingidempotencytransaction isolation

Go deeper