Movie Ticket Booking
Movie ticket booking LLD involves shows, seats, concurrent locking, payments, and confirmations — similar to BookMyShow.
Introduction
Movie ticket booking LLD involves shows, seats, concurrent locking, payments, and confirmations — similar to BookMyShow. Interviewers focus on preventing double booking and clean separation of search, seat map, payment, and notification.
Model Theater, Screen, Show, Seat, Booking, and SeatLockService. Hold seats temporarily during payment; release on timeout or failure.
Discuss read-heavy seat map vs write-heavy checkout path.
Understanding the topic
Key concepts
- Show: movie + screen + time + seat layout.
- Seat status: available, held, booked.
- Temporary hold with TTL during payment.
- Atomic multi-seat lock in one transaction.
- PaymentGateway abstraction; rollback release on failure.
- Notifier for confirmation email/SMS.
Step-by-step explanation
- User browses shows by city and movie.
- Select show; view seat map with availability.
- Select seats; system holds seats with expiry.
- User pays; on success seats marked booked.
- On failure or timeout, release hold.
- Send confirmation with booking id.
Informative example
Show seating with hold map and booking service:
public final class Show {private final String id;private final Set<String> booked = ConcurrentHashMap.newKeySet();private final Map<String, Instant> holds = new ConcurrentHashMap<>();public Show(String id) { this.id = id; }public synchronized boolean holdSeats(Set<String> seatIds, String userId, Duration ttl) {for (String s : seatIds) {if (booked.contains(s) || holds.containsKey(s)) return false;}Instant exp = Instant.now().plus(ttl);seatIds.forEach(s -> holds.put(s, exp));return true;}public synchronized void confirm(Set<String> seatIds) {seatIds.forEach(s -> { holds.remove(s); booked.add(s); });}public synchronized void releaseExpired() {Instant now = Instant.now();holds.entrySet().removeIf(e -> e.getValue().isBefore(now));}}public final class BookingService {private final Map<String, Show> shows;private final PaymentGateway payments;public BookingService(Map<String, Show> shows, PaymentGateway payments) {this.shows = shows;this.payments = payments;}public Result book(String showId, Set<String> seats, String userId, Money total) {Show show = shows.get(showId);if (!show.holdSeats(seats, userId, Duration.ofMinutes(10))) {return Result.failed("seats unavailable");}var pay = payments.charge(userId, total);if (pay instanceof PaymentResult.Failure f) {return Result.failed(f.reason());}show.confirm(seats);return Result.ok();}}
Extract SeatLockService and Booking aggregate when diagram grows; mention distributed lock for multi-server HLD follow-up.
Real-world use
Real-world applications
- Concurrency-focused LLD interview.
- Hold-and-pay workflow modeling.
- Observer for seat map live updates.
Best practices
- Hold TTL prevents indefinite blocking.
- Lock all seats in selection atomically.
- Idempotent payment callback handling.
- Separate query (seat map) from command (book).
- Clear booking status enum: HELD, CONFIRMED, CANCELLED.
Common mistakes
- Booking seats one-by-one allowing partial double book.
- No hold expiry — ghost unavailable seats.
- Payment success without confirm transition.
- God BookingSystem class with SQL strings.
Advanced interview questions
Q1BeginnerPrevent double booking?
Q2BeginnerCore classes?
Q3IntermediatePayment timeout?
Q4IntermediateLive seat map updates?
Q5AdvancedScale to multiple cities.
Summary
Show tracks booked and held seats. Atomic multi-seat hold before payment. Confirm or release on payment outcome. TTL on holds prevents seat starvation. Split search, lock, pay, notify services.