Skip to content

Two users request the last seat at once. How do you prevent overselling?

1 min read · main part only; folded sections are optional

After this you can answer: Two users request the last seat at once. How do you prevent overselling?

The lock covers one event row until commit or rollback. A second booking for the same event waits; after the first commits, it checks the updated count. Bookings for different events need not share that row lock. Plain event-list reads can see an earlier committed version without waiting for this booking.

The transaction also inserts the booking’s outbox event. An error rolls back all its writes, including any seat decrement. Replaying an idempotency key is checked before rejecting a newly sold-out event, so a successful earlier buyer can still recover their original result.

A conditional decrement with a seats-remaining predicate could also be safe inside a transaction. The explicit lock makes the distinct not-found, started and sold-out checks easier to explain. Neither choice removes a hot-event bottleneck; admission control and a clear timeout policy address that separately.

Can Redis own the last-seat guarantee?
The current Redis gate is advisory. It can drift or disappear, so the Postgres transaction remains the authority for every accepted booking.
What if inserting the booking fails?
Postgres rolls the transaction back and restores its seat decrement. A separate decrement committed before the insert would need compensation and could leak seats.
Does more API capacity solve the hot row?
It can increase the number of waiting transactions. Measure lock waits and pool pressure before scaling tasks; protecting admission may help more than adding callers.

Read Bookings row locks, then inspect the rds-postgres piece →.

apps/api/src/queries/bookings.ts → createBookingTx

Read this book online: https://book.theversehub.in/