File: hotel-reservation-system/hotel_reservation.py

Date: 2026-06-05

Time: 13:24

Purpose

This file is a self-contained implementation of a hotel reservation system designed for system design interview preparation. It owns the full booking lifecycle: hotel/room catalog management, availability search with dynamic pricing, reservation creation with optimistic concurrency control, and cancellation with tiered refund policies. It's a single-file teaching implementation — no database, no network — that demonstrates the core data modeling and concurrency concepts you'd discuss in an SDI.

Key Components

Data Classes

Custom Exceptions

HotelReservationSystem

The main class. All state lives in dictionaries:

| Field | Key | Value | Purpose |

|-------|-----|-------|---------|

| hotels | hotel_id | Hotel | Hotel catalog |

| roomtypes | (hotelid, type_id) | RoomType | Room catalog |

| inventory | (hotelid, typeid, date) | {"booked": int, "version": int} | Per-date availability tracking |

| reservations | reservation_id | Reservation | Booking records |

| idempotencykeys | key | reservationid | Dedup map for retried requests |

| seasonalpricing | (hotelid, type_id) | [(start, end, multiplier)] | Price overrides by date range |

Key methods:

daterange(checkin, checkout)

Module-level helper. Converts a [checkin, checkout) half-open date range into a list of date strings. Check-out date is excluded — matching hotel industry convention where you don't occupy the room on checkout day.

Patterns

Optimistic Concurrency Control (OCC): The reserve method implements a read-validate-write cycle. It snapshots inventory versions in Phase 1, then in Phase 2 re-reads and checks they haven't changed before committing. In a real system, Phase 2 would be atomic (e.g., a SQL UPDATE ... WHERE version = ?). Here, because it's single-threaded in-process, the version check is demonstrative — it shows the *shape* of the pattern without actual thread contention.

Idempotency Keys: reserve accepts an optional idempotency_key. If a key has been seen before, it returns the existing reservation without double-booking. This models the real-world pattern for safely retrying payment/booking requests.

Dynamic Pricing: Price is a function of state (occupancy) rather than a static lookup. This means the price you see at search time can differ from what you pay at booking time if someone else books between your search and reserve — a realistic race condition in hotel systems.

Lazy Inventory Initialization: getinventory creates {"booked": 0, "version": 0} on first access for any (hotel, type, date) tuple. No need to pre-populate dates.

Dependencies

Imports: Standard library only — dataclasses, datetime, uuid. No external dependencies.

Imported by: testhotelreservation.py, which likely contains a more thorough test suite beyond the inline test_all().

Flow

A typical booking flow:

1. Setup: addhotel + addroom_type to populate the catalog.

2. Search: Client calls search("2024-03-15", "2024-03-17", city="NYC"). The system iterates all room types, filters by city, computes per-date availability (min across the range), computes average nightly price (which includes occupancy-based surcharges), and returns matching results.

3. Reserve: Client calls reserve("h1", "std", "Alice", "2024-03-15", "2024-03-17"). The system reads and snapshots versions for March 15 and 16, verifies no version drift, computes total price, increments booked and version for both dates, creates a Reservation, and returns it.

4. Cancel: Client calls cancel(reservationid, canceltime="2024-03-01"). The system decrements booked for each date, bumps versions, computes refund based on time-to-check-in, and marks the reservation CANCELLED.

Invariants

Error Handling

Topics to Explore

Beliefs