A race condition in purchaseTickets() causes two symptoms:
undefinedOverselling — The availability check (SELECT) and decrement (UPDATE) are separate, non-transactional queries. Concurrent requests all read the same available value, all pass the check, and all decrement — pushing available negative.
undefinedDuplicate ticket numbers — Ticket numbers are computed from the same stale snapshot (total - available), so concurrent requests generate identical ranges. No UNIQUE constraint existed to catch this.
SELECT ... FOR UPDATE to lock the event row and serialize concurrent accessUNIQUE (event_id, ticket_number) and CHECK (available >= 0) constraints to init.sqlnpm run reproduce — fires 10 concurrent requests against 32 available tickets to demonstrate both issues.
We use cookies
We use cookies to analyze traffic and improve your experience. You can accept or reject analytics cookies.