What Is a Hotel Reservation System?
A hotel reservation system lets users search for available rooms, make reservations with guaranteed availability, and manage bookings. Core challenges: preventing double-booking when multiple users simultaneously reserve the last room, handling temporal inventory (a room is available or not for specific date ranges), and scaling search across millions of hotels and dates.
System Requirements
Functional
- Search hotels by location, date range, and guest count
- Check room availability for specific dates
- Reserve a room (guaranteed, no double-booking)
- Cancel a reservation
- Dynamic pricing based on occupancy and demand
Non-Functional
- No double-booking: critical correctness requirement
- Read-heavy: 100 searches per 1 booking
- 500ms search latency p99
Data Model
hotels: id, name, location, amenities, star_rating
rooms: id, hotel_id, type(single/double/suite), capacity, base_price
reservations: id, room_id, user_id, check_in, check_out, status, price
room_inventory: room_id, date, available_count -- denormalized for fast lookup
Preventing Double Booking
The critical path: two users simultaneously try to book the last available room for the same dates. Solution using optimistic locking:
BEGIN TRANSACTION;
-- Check availability with lock
SELECT available_count FROM room_inventory
WHERE room_id = ? AND date BETWEEN ? AND ?
FOR UPDATE; -- exclusive row lock
-- If all dates have available_count > 0:
UPDATE room_inventory
SET available_count = available_count - 1
WHERE room_id = ? AND date BETWEEN ? AND ?;
INSERT INTO reservations (room_id, user_id, check_in, check_out, ...) VALUES (...);
COMMIT;
FOR UPDATE locks the inventory rows for the duration of the transaction. If two users race, one waits for the lock; the second sees available_count=0 and fails. This is pessimistic locking — appropriate here because: (1) booking contention on popular hotels is real, (2) the cost of double-booking is a customer support nightmare.
Search Architecture
Full-text and geospatial search for hotels is handled by Elasticsearch (not the transactional DB). Hotels indexed with: location (geo_point), amenities (keyword), star_rating (integer), average_review_score. Search query: geo_distance filter + amenity filters + text search on hotel name/description. Results ranked by relevance + distance + rating. Availability check is separate: after Elasticsearch returns candidate hotels, check real-time availability from the transactional DB for each result (can be parallelized).
Availability Caching
Availability queries (room available on date X?) are read-heavy. Cache hotel+date availability in Redis: key = avail:{hotel_id}:{date}, value = {room_type: count}. TTL = 60 seconds (stale availability is acceptable for search display). Cache invalidated on booking or cancellation. Users see cached availability; actual booking uses DB transaction for correctness. Cache stampede prevention: probabilistic early expiration or request coalescing with a short mutex per key.
Dynamic Pricing
Price varies by: occupancy rate (higher demand = higher price), days until check-in (last-minute markup), day of week (weekend premium), and events (conferences, concerts near the hotel). Pricing engine runs every 30 minutes as a batch job, updates price_adjustments table. Room display price = base_price * (1 + adjustment_factor). For the reservation itself, the price is locked at booking time — price displayed = price charged.
Interview Tips
- Double-booking prevention is the central correctness challenge — FOR UPDATE transaction is the standard answer.
- Search (Elasticsearch) and booking (RDBMS) are separate — don’t try to do geospatial search in PostgreSQL at scale.
- room_inventory table (denormalized by date) enables fast date-range availability queries vs. computing from reservations on the fly.
- Cache invalidation on booking ensures search results don’t show unavailable rooms for long.