LLD Hub
lldconcurrencyobserverstrategy

How to Design an Event Ticketing System (Ticketmaster) | LLD

Design a high-concurrency ticket booking system with seat holds, waiting lists, dynamic pricing, and overselling prevention. Advanced LLD for senior engineers.

19 April 2025·9 min read

Practice this problem

Event Ticketing System — get AI-scored feedback on your solution

Solve it →

The Event Ticketing System (like Ticketmaster) is an advanced LLD problem that combines high concurrency handling, waiting lists, dynamic pricing, and complex state management. It's asked for senior SDE roles at companies handling high-traffic sales events.

Core Entities

  • Event — name, venue, date, ticket categories
  • Venue — sections, seat map
  • Ticket — category (GA/VIP/Seated), price, status
  • Order — user, tickets, status, payment
  • SeatHold — temporary reservation with 5-minute expiry
  • WaitingList — FIFO queue per event/category
  • PricingEngine — demand-based dynamic pricing

Seat Hold with Concurrency Control

class TicketingService {
  holdTickets(eventId: string, category: string, qty: number, userId: string): SeatHold {
    // Optimistic locking: version field on TicketInventory
    const inventory = this.inventoryRepo.get(eventId, category);
    if (inventory.available < qty) throw new Error("Not enough tickets");

    const hold = new SeatHold(userId, eventId, category, qty, 5 * 60 * 1000);
    // Atomic decrement — DB handles concurrent access
    this.inventoryRepo.decrementAvailable(eventId, category, qty, inventory.version);
    this.holdRepo.save(hold);
    this.scheduleHoldExpiry(hold);
    return hold;
  }

  private scheduleHoldExpiry(hold: SeatHold) {
    setTimeout(() => {
      if (hold.status === HoldStatus.PENDING) {
        this.releaseHold(hold.id);
        this.notifyWaitingList(hold.eventId, hold.category, hold.qty);
      }
    }, hold.expiryMs);
  }
}

Waiting List with Observer

class WaitingListService {
  join(userId: string, eventId: string, category: string, qty: number): WaitingEntry {
    const entry = new WaitingEntry(userId, eventId, category, qty);
    this.queue.enqueue(eventId + category, entry);
    return entry;
  }

  notify(eventId: string, category: string, availableQty: number) {
    while (availableQty > 0) {
      const next = this.queue.peek(eventId + category);
      if (!next || next.qty > availableQty) break;
      this.notificationService.send(next.userId, "Tickets available! You have 10 minutes.");
      next.status = WaitingStatus.NOTIFIED;
      availableQty -= next.qty;
    }
  }
}

Dynamic Pricing Strategy

class DemandBasedPricing implements PricingStrategy {
  getPrice(basePrice: number, soldPct: number): number {
    if (soldPct < 0.5)  return basePrice;
    if (soldPct < 0.75) return basePrice * 1.2;
    if (soldPct < 0.9)  return basePrice * 1.5;
    return basePrice * 2.0; // High demand
  }
}

Ready to practice?

Submit your solution and get AI-scored feedback on OOP, SOLID principles, design patterns, and code quality.

Solve Event Ticketing System