How to Design an Airline Reservation System?
Learn how to design an airline reservation system: seat holds, optimistic locking, sagas, and idempotency to prevent double-booking.
Expected Interview Answer
An airline reservation system is designed around a strongly consistent seat-inventory service that uses optimistic locking or short-lived holds to prevent double-booking, backed by an event-driven pricing and search layer that can scale horizontally without touching the transactional core.
The core challenge is that seat inventory is a scarce, contended resource: thousands of clients may try to book the last seat on a flight at once, so the booking service needs a transactional data store (often a relational database) with row-level locking or optimistic concurrency (version numbers) around the seat map, plus a short-lived “hold” state so a seat is reserved for a few minutes while payment completes. Search and pricing, by contrast, are read-heavy and eventually consistent, so they run on denormalized, cached read replicas or a search index (Elasticsearch) that is asynchronously updated from booking events. A saga or outbox pattern coordinates the multi-step booking flow (hold seat, charge payment, issue ticket, notify) so a failure partway through triggers compensating actions like releasing the hold instead of leaving inconsistent state. Idempotency keys on booking requests protect against duplicate charges from client retries.
- Optimistic locking and short holds prevent double-selling the same seat under load
- Splitting read-heavy search from write-heavy booking lets each scale independently
- A saga/outbox pattern keeps multi-step bookings consistent despite partial failures
- Idempotency keys make retried requests safe, avoiding duplicate charges or bookings
AI Mentor Explanation
Designing an airline reservation system is like managing the exact eleven spots on a team sheet when hundreds of players are vying for a place before the toss. The selector places a name in a slot only provisionally (a hold) until the fitness test and paperwork clear, and if two names collide for the same spot, only one is confirmed while the other is bounced back to the pool. A version number on the sheet stops two selectors from both thinking they finalized the same slot at once. That careful, contended slot-by-slot confirmation is exactly how seat inventory is protected from double-booking.
Step-by-Step Explanation
Step 1
Search and price
A read-optimized search service queries denormalized, cached flight/fare data updated asynchronously from the booking core.
Step 2
Hold the seat
The booking service places a short-lived hold on a specific seat using optimistic locking (a version number) so two requests cannot both claim it.
Step 3
Process payment and confirm
A saga coordinates payment capture and ticket issuance; an idempotency key ensures retried requests never double-charge or double-book.
Step 4
Compensate on failure
If any step fails (payment declined, ticketing error), compensating actions release the seat hold and refund any captured payment.
What Interviewer Expects
- Identifies seat inventory as the contended, strongly consistent core versus search/pricing as read-heavy and eventually consistent
- Explains a concrete concurrency control mechanism: optimistic locking, version numbers, or short-lived holds
- Describes a saga or outbox pattern for the multi-step booking workflow with compensating actions
- Mentions idempotency keys to make retries safe against duplicate bookings or charges
Common Mistakes
- Treating the whole system as one monolithic read/write path instead of splitting search from booking
- Ignoring double-booking risk under concurrent requests for the same seat
- Forgetting compensating transactions when a downstream step (payment, ticketing) fails mid-flow
- Not mentioning idempotency for client retries on flaky networks
Best Answer (HR Friendly)
“An airline reservation system separates two very different problems: searching and pricing flights, which can be fast and slightly stale, and actually booking a seat, which must be perfectly accurate so no seat is ever sold twice. We protect the seat-booking step with short holds and version checks, and we use a step-by-step workflow with automatic rollback so if payment or ticketing fails partway through, everything cleanly unwinds.”
Code Example
def hold_seat(flight_id, seat_id, user_id, hold_seconds=300):
seat = db.get_seat(flight_id, seat_id)
if seat.status != "available":
raise SeatUnavailableError(seat_id)
updated = db.execute(
"UPDATE seats SET status = 'held', held_by = %s, "
"held_until = NOW() + INTERVAL '%s seconds', version = version + 1 "
"WHERE id = %s AND flight_id = %s AND version = %s",
[user_id, hold_seconds, seat_id, flight_id, seat.version],
)
if updated.row_count == 0:
# another request changed the seat first; version mismatch
raise SeatConflictError(seat_id)
return {"seatId": seat_id, "heldUntil": updated.held_until}
def confirm_booking(flight_id, seat_id, payment_token, idempotency_key):
if db.booking_exists(idempotency_key):
return db.get_booking(idempotency_key) # safe retry
payment = charge_payment(payment_token)
if not payment.success:
release_hold(flight_id, seat_id)
raise PaymentFailedError()
return db.create_booking(flight_id, seat_id, idempotency_key)Follow-up Questions
- How would you prevent two customers from booking the same seat at the exact same millisecond?
- What happens if the payment step succeeds but the ticket-issuance step then fails?
- How do you keep the flight search index fresh without slowing down the booking transaction?
- How would you handle a customer retrying a booking request after a network timeout?
MCQ Practice
1. What concurrency technique prevents two requests from booking the same seat simultaneously?
A version number on the seat record lets the update fail if another request already changed it, preventing double-booking.
2. Why does an airline reservation system separate flight search from seat booking?
Search is high-volume and read-heavy, so it scales via caches/replicas, while booking touches scarce, contended seat inventory and needs strong consistency.
3. What does an idempotency key protect against in a booking flow?
An idempotency key lets the server recognize a retried request and return the original result instead of creating a duplicate booking or charge.
Flash Cards
Why split search from booking in an airline system? — Search is read-heavy and can be stale; booking touches scarce seat inventory and needs strong consistency.
How do you stop double-booking a seat? — Optimistic locking (version numbers) or short-lived holds during the booking transaction.
What handles a multi-step booking failure? — A saga/outbox pattern with compensating actions, like releasing a seat hold if payment fails.
Why use idempotency keys on booking requests? — So a retried request returns the original result instead of creating a duplicate booking or charge.