Design BookMyShow With Concurrent Seat Locking
In a 45-minute LLD interview, this problem is the gold standard for high-concurrency reservation systems under flash-sale loads. Scope the architecture to: multiple cinemas/screens/shows, atomic all-or-nothing multi-seat locking, inline TTL-based hold expiration, non-blocking external payment processing, and checkout pipeline orchestration via a Facade. Distributed Redis locks or database write-ahead logging can be discussed as scale-out extensions.
Problem statement & clarifying requirements
Design a movie ticket booking platform like BookMyShow that supports multiple cinemas, screens, and shows. The core challenge is handling concurrent seat reservations under heavy flash-sale traffic: when hundreds of users race to book the exact same seats, the system must guarantee zero double-bookings, provide an atomic temporary seat hold with a Time-To-Live (TTL) during payment, and automatically release held seats if payment times out or fails.
Seat locking must be strictly atomic and mutually exclusive. Exactly one user acquires the lock; all competing requests fail immediately with a conflict signal.
Each lock has a configurable TTL (e.g. 5β10 minutes). If confirmation does not arrive before the deadline, the seat automatically transitions back to available without requiring an explicit background cleanup sweep.
Yes. Multi-seat reservations follow all-or-nothing atomicity. If even one requested seat is unavailable, none are held.
A BookingFacade coordinates the checkout pipeline: holding inventory, delegating payment to a gateway, confirming the seat status upon success, and issuing a serialized ticket.
First, sketch the design yourself
Spend 5 minutes listing the classes, who owns whom, and which interface hides the part that changes.
- 1.
Distinguish between permanent booking and temporary hold: a seat cannot jump straight from
AvailabletoBookedbecause online payments take seconds to complete. - 2.
Avoid coarse-grained global locks across the entire cinema: scope synchronization to the specific show or seat partition using thread-safe data structures.
- 3.
Decouple domain subsystems: the caller screen should interact with a single unified Facade interface rather than orchestrating lock managers, payment gateways, and ticket databases manually.
How to think through this problem (5-step walkthrough)
In a 45-minute LLD interview, this problem is the gold standard for high-concurrency reservation systems under flash-sale loads. Scope the architecture to: multiple cinemas/screens/shows, atomic all-or-nothing multi-seat locking, inline TTL-based hold expiration, non-blocking external payment processing, and checkout pipeline orchestration via a Facade. Distributed Redis locks or database write-ahead logging can be discussed as scale-out extensions.
Not every noun in the prompt deserves its own class. Separate dumb data structs from stateful managers, and turn trivial nouns into fields or enums.
BookingFacadeFacade orchestrating end-to-end checkout: coordinates seat locking, payment gateway charges, seat confirmation, and ticket issuing while shielding clients from subsystem complexity.
SeatLockManagerThread-safe manager maintaining seat availability per show, enforcing atomic all-or-nothing locking and evaluating inline TTL expirations under a mutex.
ShowSeatDomain record representing a seat in a show, tracking state (Available, Held, Booked), current holder user ID, and lock expiration deadline timestamp.
PaymentGatewayStrategy interface abstracting third-party payment processing (processPayment()), returning transaction receipts without holding inventory mutexes.
TicketImmutable value struct confirming a completed booking with booking ID, show reference, confirmed seat IDs, and payment details.
SeatHoldTimerThreadTrap noun β beginner candidates often spawn a background std::thread per held seat with a sleep_for(TTL) to release it. With thousands of concurrent users, this exhausts OS thread limits; seat lock expiration must be evaluated inline lazily by timestamp comparison (now > lockExpiration) under the lock.
A naive implementation locks seats one-by-one in a loop (for (auto id : seatIds) lockSeat(id)). If User A locks seat 1 and User B locks seat 2 while both want seats [1, 2], a deadlock occurs or seats are left partially locked when one fails. Furthermore, holding a mutex while calling an external HTTP payment gateway causes thread starvation, bringing the entire booking portal to a complete crawl during flash sales.
Exposing raw seat locks and payment APIs directly to API controllers leads to scattered rollback code and leaked locks upon payment failure.
Treating seats as a binary boolean isBooked ignores the temporary hold window required while users complete payment authorization.
Directly coupling checkout to a specific payment provider prevents unit testing with mock gateways and makes adding alternate providers difficult.
- β
All-or-nothing atomic seat locking: When a user requests multiple seats, all seats must be verified as available before any seat's status is mutated to
Held. If any seat is unavailable or held by another user with an active TTL, the entire batch fails with zero side effects. - β
Zero mutex retention during external I/O: The
SeatLockManagermutex is held only for microseconds during the in-memory state transition fromAvailable β HeldorHeld β Booked. It is never held while callingPaymentGateway::processPayment(). - β
Lazy inline TTL evaluation: A seat marked
HeldwhoselockExpirationtimestamp is less thannow()is treated as immediatelyAvailableby subsequent locking attempts, avoiding wasteful background timer threads.
Entities & design patterns used
Unlock Full UML Diagram & C++23 Solution
The complete UML diagram, production-ready C++23 code, follow-up extensions, and design pitfall analysis are part of Brute2Best Pro. All 7 foundation chapters are 100% free.
First anchor question per pattern, Part 1 LLD & Module 1 C++ basics are 100% Free forever.