Distributed Seat Locking
Exactly one winner per seat — enforced atomically, verified again at payment, and correct even when holds expire mid-flow.
User A → Booking API → Redis
The hold
User A selects seat 14C for a shuttle-pass window and the seat is held immediately — a single atomic Redis operation (Redis + Lua) with a 2-minute TTL. One hold covers the entire 30–45 day subscription window, so this isn't one ride at stake.
Why not the alternatives?
- Database row locks
- Holding a DB lock through user think-time and a payment flow pins connections for minutes. Under booking-rush contention that exhausts the pool and takes unrelated queries down with it.
- Optimistic locking
- Works when conflicts are rare. Seat booking at peak is the opposite — high contention on identical rows — and 'sorry, try again' after entering payment details is hostile UX.
- TTL-only expiry (no explicit release)
- Tried, effectively — and it produced the self-lockout problem in production. Expiry is the safety net for crashes, not a substitute for releasing holds on every known exit path.
- Trusting payment success as booking authority
- A completed payment with an expired hold must not produce a booking — otherwise slow payments can double-sell a seat. The hold_token check at confirmation keeps the hold, not the money, as the source of truth; the late payment is cancelled and refunded instead.
Lessons
- Atomicity is the foundation, but release paths are the feature: every way a user can leave the flow needs a corresponding way for the hold to die.
- Copying a pattern (BookMyShow-style holds) imports its assumptions; production is where you find out which assumptions weren't yours.
- Verify the lock again at commit time — a hold that was valid when payment started may not be valid when payment lands, and correctness depends on the second check.
- Fail fast before money moves, reallocate gracefully after — the layer where you handle a conflict matters as much as handling it.
- Third-party eventual consistency is your problem, not the provider's — design a grace window rather than surfacing a transient state as a final answer.
Now try to break it
You've read how the lock is designed. The simulator gives you two phones and eight seats — take the same seat twice, let a hold expire, pay with a dead token, and watch which defense stops you.
Open the simulator →