Кейс: сервис записи к врачу / бронирование слотов

↑ 8.4 Backend System Design · ← Предыдущая · → Следующая

Обязательно~3 мин чтенияУровень: senior

Зачем это на собесе

Задача на конкурентность: два пользователя не должны занять один слот.

Объяснение

Требования: показать расписание врача, забронировать слот, отменить/перенести, напоминания, не допустить двойной брони, выдерживать пики (открытие записи), уметь работать по часовым поясам.

Модель:

schedule(id, doctor_id, date, start, end, capacity)
slot(id, doctor_id, start_time, end_time, status)          -- free / held / booked
booking(id, slot_id, patient_id, status, created_at)
UNIQUE (slot_id) WHERE status IN ('held','booked')          -- защита от двойной брони

Защита от двойного бронирования:

СпособПример
Уникальный индексCREATE UNIQUE INDEX ... ON booking(slot_id) WHERE status <> 'cancelled'; нарушение = «слот занят»
Условное обновлениеUPDATE slot SET status='booked' WHERE id=@id AND status='free' (проверить число затронутых строк)
Оптимистичная блокировкаверсия строки
SELECT ... FOR UPDATEпессимистичная блокировка слота
Redis-лок на слотдоп. защита при частых конфликтах; не единственная

Удержание слота (hold): пользователь выбирает слот → он «удерживается» на 5–10 минут (TTL), затем подтверждение/оплата; фоновая задача возвращает просроченные удержания.

sequenceDiagram
  participant U as Пациент
  participant A as API
  participant DB as БД
  U->>A: выбрать слот
  A->>DB: UPDATE slot SET status='held', held_until=now()+10m WHERE id=@id AND status='free'
  DB-->>A: 1 строка → удержан
  U->>A: подтвердить
  A->>DB: UPDATE ... SET status='booked' WHERE id=@id AND held_by=@u AND held_until>now()
  A-->>U: запись создана + событие BookingConfirmed

Прочее: расписание кэшируется (Redis) с инвалидацией по изменению; напоминания — планировщик и очередь уведомлений (см. Кейс: система уведомлений); аудит и персональные данные пациентов (шифрование, аудит доступа); часовые пояса хранятся как UTC + зона клиники; интеграция с МИС (см. FHIR).

Нюансы и подводные камни

  • Проверка «слот свободен» отдельным SELECT перед INSERT — классическая гонка.
  • Пики при открытии записи: очередь ожидания, rate limiting.
  • Двусторонняя интеграция с внешней системой расписаний: конфликты и сверка.
  • Отмена и перенос — тоже конкурентные операции.
  • Права: пациент видит только свои записи.

Практика

  1. Реализуйте бронирование с уникальным индексом и проверьте гонку 100 параллельных запросов.
  2. Добавьте удержание слота с TTL и фоновую очистку.
  3. Опишите поведение при одновременных бронировании и отмене.

Вопросы с ответами

Связанные темы