The Lock That's Too Expensive to Hold
The textbook database answer to two people booking the same seat, and the math that proves you can never hold that lock for an entire payment flow.
Checkout's two-step pattern explains why a seat gets reserved the moment someone moves to pay, but that reservation still needs a real mechanism behind it, one that stops two people from booking the same seat on the backend.
Two People, One Pay Button, Same Instant
Picture two people, P1 and P2, clicking pay at the exact same moment. P1 is booking seats 2 and 5. P2 is booking seats 5, 7, and 9.
Seat 5 overlaps. Only one of them can be let through to the payment screen.
The Textbook Answer: Serializable Isolation
Most relational databases have an isolation level called SERIALIZABLE. If two transactions (two separate requests trying to read or write data at the same time) try to touch the same row at once, it only lets one of them through. The other one waits.
If a query has been waiting too long, say a couple of seconds, the practical move is to just treat it as failed. Show the user an error and let them try again, rather than leaving them stuck wondering what happened.
Why Holding That Lock for Two Minutes Is a Disaster at Scale
Here's where it gets interesting. P1 wins the lock and gets taken to the payment screen. Card details, UPI, a countdown timer. On average, paying takes about two minutes.
So here's the real question: for how long should that database lock stay held? A tempting first answer is simple: keep it locked until payment succeeds, fails, or the person presses back.
That answer breaks the moment you look at the numbers.
Say, at any given instant, 100,000 people across the platform are all mid-payment somewhere, which isn't unusual at BookMyShow's scale. If a database lock stays held for the whole payment, every one of those 100,000 people is holding a lock right now, for the full two minutes it takes them to type in card details.
ExpandA brief lock around checking seat status is fine, but holding that same lock for the entire two-minute payment flow multiplies into roughly 100,000 simultaneous locks at BookMyShow's scale
That many open locks makes the database slow. CPU usage climbs. Memory usage climbs. None of it helps anyone actually get their ticket faster.
A database lock should never be held for the length of an entire payment flow. Whatever the real answer turns out to be, it has to release that lock far sooner than "when the payment finishes."
The Algorithm So Far
Here's the shape of the book-ticket logic, as far as it goes before the lock question gets resolved:
- Get the requested seats.
- Check the status of each one.
- If any seat isn't available, stop immediately. Reject the whole booking.
- If every seat is available, proceed.
Steps one and two need to happen inside a lock. If P1 and P2 both read the same three seats as available at the same instant, before either has written anything, both will conclude the booking can go ahead. The read itself has to be protected, not just the eventual write.
So a lock has to guard reading and checking the seats. That part is settled.
Here's the open question this leaves: the lock releases the instant that check passes, seconds into the flow, but the seat still needs to stay off-limits to everyone else for the next two minutes while P1 pays. How does a seat stay locked out with no lock actually held? That's the exact problem the next post solves.
Keep reading