BookMyTicket
July 1, 2026
BookMyTicket is a distributed event-ticketing platform designed to solve one of the hardest problems in ticketing systems: ensuring that no two users can book the same seat, even when requests arrive simultaneously.
- Source Code available at: github.com/akshatddyl/BookMyTicket
The Problem
Popular events generate bursts of concurrent booking requests. The challenge is guaranteeing that exactly one user can reserve a seat while handling payment failures and service crashes without leaving seats permanently locked or oversold.
Tech Stack
SETNX + TTL)Architecture & Implementation
All requests pass through Spring Cloud Gateway, which validates JWTs once and forwards trusted user claims to downstream services. The booking-service orchestrates the booking flow:
- Reserve seats through inventory-service using Redis distributed locks.
- Create a
PENDINGbooking. - Process payment through payment-service.
- Publish a Kafka event indicating success or failure. After that, the workflow becomes event-driven: - inventory-service confirms or releases seats. - notification-service sends booking confirmations or failure notifications. This hybrid approach keeps critical user-facing operations synchronous while allowing post-booking tasks to remain loosely coupled.
Challenges & Trade-offs
The genuinely hard problem was making the seat-locking step atomic across two different data stores at once — Redis for the lock, Postgres for the seat's real status. The lock only counts if both agree: SETNX in Redis establishes "who got here first," and the seat's status in Postgres is re-checked before committing, so a lock acquired on stale data still gets rejected. Rolling back partial Redis locks on any failure was the piece I got wrong first — an early version left orphaned locks behind on partial failures, which is exactly the kind of bug that only shows up once someone tries to book several seats at once and one of them is already taken.
The clearest deliberate trade-off is mixing synchronous and asynchronous communication rather than making everything one or the other. Seat-locking and payment are synchronous REST calls because the caller genuinely needs an immediate answer — "did I get the seat, did the payment go through." That's also the trade-off's cost: if inventory-service or payment-service is down, booking fails immediately rather than degrading gracefully. Everything after the outcome is known — updating inventory, notifying the user — is async over Kafka, because nothing in that path needs to block the user's response, and new consumers (analytics, SMS, whatever) can subscribe later without booking-service ever changing.
What I Learned
- Learned the practical difference between orchestration and choreography in a saga — booking-service actively drives the synchronous, must-succeed-now steps, while Kafka lets the once-the-outcome-is-known steps happen independently without central coordination.
- Learned to treat a distributed lock's TTL as a correctness feature, not just a cleanup mechanism — it's what keeps a crashed request from permanently blocking a seat.
- Learned to centralize authentication at the API gateway using JWT claims forwarded as trusted headers, instead of re-verifying tokens in every service that receives a request.