· 1 мин чтения
Двойная бронь: транзакция плюс частичный UNIQUE-индекс
Как booking-slots защищается от двух клиентов, которые одновременно записываются на одно время, и чем проверяется эта защита.
Классическая гонка: два клиента одновременно видят свободный слот и оба нажимают «записаться». Одной проверки «свободно ли» в коде недостаточно: между проверкой и вставкой может вклиниться второй запрос.
Первая линия: транзакция
В Book пересчёт свободных слотов и вставка записи выполняются в одной транзакции. Слот, которого нет среди свободных, даёт ErrTaken (или ErrPast, если время уже прошло).
Вторая линия: индекс
База сама не даст создать дубль:
CREATE UNIQUE INDEX IF NOT EXISTS ux_bookings_active_start
ON bookings(date, start_min) WHERE status = 'active';
Индекс частичный: он действует только для активных записей, поэтому отменённая запись освобождает время. Если вставка упирается в индекс, код превращает ошибку в тот же ErrTaken, и клиент получает 409.
Чем проверено
Тест запускает 30 горутин на одно и то же время: успешной должна быть ровно одна запись.
Границы
Это защита от двойной брони одного ресурса: все услуги делят одно расписание, и модель с несколькими специалистами потребует другого индекса. Об этом сказано в ограничениях проекта.