Ticket Booking (Shows / Flights)
Problem statement
Sell limited seats fairly under massive concurrency (concert on-sale), prevent overselling, handle seat holds, payment timeout, and waitlists.
How it works
- Hold: temporarily reserve seat IDs with TTL (e.g. 10 minutes).
- Confirm: on payment success, convert hold to sold immutable record.
- Release: TTL expiry or payment failure frees seats.
Analogy: Theater hold line: the agent puts a sticky note on 4 seats for 10 minutes while you run to the ATM; if you’re late, notes are removed.
High-level design
Rendering diagram…
Components explained — this design
| Component | What it is | Why we use it here |
|---|---|---|
| API Gateway + WAF + queue token | Edge protection + optional waiting room token. | Prevents instant sell-out bots from melting inventory service. |
| Virtual waiting room | Admission control (CF Workers / vendor). | Absorbs flash crowd; issues signed tokens to enter purchase flow fairly. |
| Booking service | Holds seats, coordinates payment, commits order. | Encapsulates saga steps and idempotency for checkout retries. |
| Redis hold locks | Short TTL locks on seat/slot keys. | Fast optimistic reservation; expires automatically if user abandons cart. |
| PostgreSQL | Durable inventory and booking rows. | Unique constraints are final anti-double-sell guardrails. |
| Stripe auth hold | Pre-authorizes funds without final capture. | Reduces no-show revenue loss while avoiding capturing before seat confirmed. |
| POS webhook | External truth for table availability. | Bridges online inventory with in-restaurant reality. |
Shared definitions: 00-glossary-common-services.md
Low-level design
Concurrency control
- Pessimistic:
SELECT ... FOR UPDATEon seat rows — serializes; bad at huge fan-in. - Optimistic: version column — many 409 conflicts on hot events.
- Preferred for hot rows: Redis Lua script atomic
HSETNX seat:F12+ expire; async reconcile to PostgreSQL with outbox pattern.
Waiting room
- CloudFront + Lambda@Edge or Cloudflare Waiting Room to absorb burst; issue signed “shop token” admitting users gradually.
Idempotency
- Idempotency-Key on checkout; unique (event_id, seat_id) constraint as final guard.
Search vs lock
- OpenSearch for “find shows near me”; inventory remains source of truth in SQL.
E2E: purchase two adjacent seats
Rendering diagram…
Tricky parts
| Problem | Solution |
|---|---|
| Double sell | DB unique constraint + Redis as admission control only |
| Bots | Proof-of-work, CAPTCHA, device attestation |
| Fairness | Lottery after waiting room vs pure FCFS |
Caveats
- Airline GDS integration (Amadeus) is slow — design async holds + callback webhooks.
- Refunds/chargebacks need compensating transactions (Saga).
Azure
- Azure Queue for admission; SQL Server with rowversion; Front Door + WAF.