CCLab
CC
Email me

A marketplace of graded cards has exactly one of each. When two buyers press Buy on the last one at the same moment, both requests can read “one left”, both pass the check, and both take payment. Each line of that code is correct, and it still sells a card twice, because the check and the decrement are separate steps that another request can slip between.

The fix is to let the database settle the race. Lock the row, or make the decrement conditional, and the second checkout waits, reads the fresh stock and sees the card is gone. SwishX, which I architected and built via Lazer, sells real graded cards, so its checkout had to be oversell-proof.

Model
A TypeScript state machine, two buyers, one card
Interleaving
Fixed, so every run is reproducible
Scope
Generic, not SwishX’s code
Case study
Read the case study →

Two buyers, one card

Press Race to send two buyers for the last card.

Checkout

Buyer A

Order confirmed

Cards left

−1

Row unlocked

Buyer B

Order confirmed, but the card is gone

  1. A Reads the stockSELECT stock → 1Cards left: 1
  2. B Reads the stockSELECT stock → 1Cards left: 1
  3. A Sees one left, takes payment1 > 0 ✓ · chargeCards left: 1
  4. B Also sees one left, takes payment1 > 0 ✓ · chargeCards left: 1
  5. A Order confirmedUPDATE stock = stock − 1 → 0Cards left: 0
  6. B Order confirmed, but the card is goneUPDATE stock = stock − 1 → −1Cards left: −1

Oversold: two paid orders for one card, stock −1.

A generic demo of the race a marketplace checkout has to handle, not client code.

Example result

Without a lock, both buyers pay and the stock ends at −1. Both see “Order confirmed”, and one of them has paid for a card that doesn’t exist.

With a lock, the second buyer waits for the row, reads the updated stock and gets “Sold out” before any payment is taken. One order goes through, and the stock ends at 0.

Read the case study →All demos

Questions