Train Booking Backend: A High-Concurrency Microservices Ecosystem

Distributed Full-Stack Ticketing Ecosystem with Event-Driven Seat Reservations.

Overview

I designed and built a robust, microservices-based backend for a high-concurrency train booking platform. The architecture consists of five specialized services: an API Gateway, User Authentication, Booking Management, Fuzzy Search via ElasticSearch, and a Payment Service with reliable webhook processing. The system is engineered to handle extreme traffic spikes—modeled after 'Tatkal' booking scenarios—where thousands of users compete for the same limited resources simultaneously. I built this project to master the complexities of distributed systems, specifically focusing on the 'double booking' problem and the reliability of financial transactions across service boundaries. I implemented a multi-layered concurrency strategy using Redis for fast, short-lived seat locks and PostgreSQL for durable, row-level transaction isolation.

Problem

The primary challenge in train booking systems is managing extreme contention where thousands of concurrent requests attempt to reserve the same limited set of seats. Core challenges included: • Distributed Race Conditions: Multiple users could be assigned the same seat if concurrent requests aren't handled with strict, cross-instance locking. • Request Duplication: Network instability often causes clients to retry requests, which can lead to duplicate bookings or multiple charges if not handled idempotently. • System Decoupling: A monolithic design would struggle to scale individual bottlenecked components (like search or payments) independently under heavy load.

Constraints

  • Strict Data Consistency: The system must ensure a seat is never double-booked, even under millisecond-level contention across multiple service instances.
  • Financial Reliability: Payment confirmations must be processed reliably, even if the booking service is temporarily down, requiring a fault-tolerant messaging layer.

Solution

I adopted a microservices architecture using Node.js and TypeScript to decouple the platform’s core domains. For the critical seat allocation logic, I implemented a 'Reservations Pattern': a Redis SETNX lock provides an initial, low-latency guard to reject early enthusiasts, followed by a PostgreSQL FOR UPDATE row lock within a database transaction for definitive consistency. To ensure the system is resilient to network failures, I integrated an idempotency layer across all transactional endpoints using custom headers to safely allow client retries. I utilized RabbitMQ for asynchronous service orchestration, allowing the Payment Service to notify the Booking Service of successful transactions via an event-driven flow. For searching routes across large datasets, I integrated ElasticSearch to provide low-latency, fuzzy-matching capabilities that offload expensive queries from the primary relational database.

Architecture

The API Gateway acts as the single entry point, handling rate limiting and authentication before routing requests. Services communicate asynchronously via RabbitMQ exchanges to ensure eventual consistency and fault tolerance, particularly during the payment-to-booking confirmation flow.

backend:Node.js (Express), TypeScript, Docker Compose.

database:PostgreSQL (Persistence), Redis (Caching & Distributed Locking).

communication:RabbitMQ (Asynchronous Events), HTTP Proxy (API Gateway).

search:ElasticSearch.

libraries:

  • amqplib
  • ioredis
  • pg-pool
  • http-proxy-middleware
  • helmet
  • express-rate-limit

Trade-offs

Microservices over Monolith: I chose scalability and service independence at the cost of increased operational complexity. Eventual Consistency for Payments: I used RabbitMQ for payment confirmations, accepting a slight delay in updates for a highly decoupled pipeline. Multi-Layer Locking: I implemented both Redis and SQL-level locking to reduce overhead on the primary database during high contention.

Learnings

Concurrency Control: Mastered the implementation of distributed locking strategies to solve race conditions in a multi-instance, high-traffic environment. Idempotency Patterns: Gained deep experience in designing idempotent APIs that handle the 'at-least-once' delivery guarantees of modern web clients. Infrastructure Management: Learned the nuances of managing a containerized microservices stack, including service discovery and automated migrations.

Future Roadmap

  • Observability Stack: Integrate Prometheus and Grafana for real-time monitoring of service health and queue lengths.
  • Circuit Breaker Pattern: Implement libraries like Opossum to prevent cascading failures when downstream services are unavailable.
  • Saga Pattern: Implement a formal Saga Coordinator for more complex distributed transactions involving multiple services.

Summary of Work

  • Concurrency Architecture

    Developed a dual-layer locking system using Redis SETNX and Postgres SELECT FOR UPDATE.

  • Microservice Orchestration

    Managed 1 total containers orchestrating Postgres, Redis, RabbitMQ, and ElasticSearch.

  • Reliability Engineering

    Implemented Idempotency-Key headers and RabbitMQ DLQs (Dead Letter Queues) for 100% financial reliability.

  • Fuzzy Search Integration

    Optimized route discovery by offloading complex fuzzy queries to an ElasticSearch cluster.

Kashish Gadhiya — Full-Stack Developer & AI Enthusiast