Flash Sales
A flash sale is a time-boxed discount with a hard unit cap. The interesting engineering is not the discount — it is making sure that when a thousand shoppers all hit “buy” on the last ten units, exactly ten orders succeed.
The oversell problem
The naive approach — read the sold count, compare to the limit, then increment — has a race: two requests both read “9 of 10 sold”, both decide they may proceed, and both write “10”. Eleven units sold against a cap of ten.
This platform solves it with atomic, Redis-backed inventory counters.
Atomic claims with Redis + Lua
FlashSaleInventoryService keeps the authoritative sold count in Redis while a
sale is live:
flash_sale:{id}:inventory:sold → "42"
Every mutation runs as a single Lua EVAL, so the read-check-write
sequence is atomic on the Redis side — no WATCH/MULTI/EXEC dance:
-- claim qty units against limit, atomically
local sold = tonumber(redis.call('GET', KEYS[1]) or '0')
local limit = tonumber(ARGV[1])
local qty = tonumber(ARGV[2])
if sold + qty > limit then
return -1 -- sold out
end
return redis.call('INCRBY', KEYS[1], qty)
A claim either returns the new sold count or -1 for “sold out”. There is no
window in which two callers can both see the last unit as available.
Graceful degradation
Redis is a fail-open dependency here too. If
Redis is unavailable, callers fall back to a PostgreSQL conditional UPDATE
in FlashSale#claim_unit! — slower, but still correct and still impossible to
oversell. The DB path is kept intact and tested precisely so the Redis fast
path can fail safely.
PostgreSQL (flash_sales.quantity_sold) is kept in sync asynchronously by
FlashSaleUnitsUpdateJob after every order, so admin and reporting views stay
accurate without sitting on the hot path.
Cart reservations
Before checkout, FlashSaleReservationService places a time-bounded hold
so a shopper’s cart item is not snatched away mid-purchase:
- For unlimited sales, reservations are purely advisory — they drive urgency UX (“reserved for 10:00”) without consuming capacity.
- For quantity-limited sales,
reserve!checks available capacity inside a pessimistic row lock, so concurrent requests cannot double-book the last unit. Availability is computed aslimit − sold − reserved-by-everyone-else.
Notifications
When a sale goes live, background jobs fan out alerts — including to shoppers who have a sale product sitting in a wishlist — over email and web push.
Key files
| Concern | Files |
|---|---|
| Models | FlashSale, FlashSaleProduct, FlashSaleReservation, FlashSaleNotification |
| Services | FlashSaleInventoryService, FlashSaleReservationService, FlashSaleService, FlashSalePreflightValidator |
| Jobs | FlashSaleActivationJob, FlashSaleUnitsUpdateJob, FlashSaleExpirationJob, FlashSaleWishlistNotificationJob |