Предотвращение двойных бронирований: почему системы дают сбой, и модель, которая не может

Двойное бронирование почти никогда не возникает из-за того, что календарь «ошибся». Оно возникает потому, что программа проверяла, свободен ли слот, и резервировала его двумя отдельными шагами с зазором между ними — и второй клиент проскочил в этот зазор. Закройте этот зазор — и всё остальное в календаре может быть настолько простым или сложным, насколько захотите. Оставьте его открытым — и никакая полировка виджета бронирования не помешает время от времени двум людям попадать на одно и то же место.

Где на самом деле возникает разрыв

Обычная последовательность почти любого бронирования: проверить «этот слот ещё свободен?», получить «да», а затем записать бронирование. Чтение, потом запись — и между ними, пусть даже на мгновение, открывается окно. Второй запрос, проверяющий тот же слот в этом окне, тоже видит «да, ещё свободен». Оба теперь уверены, что бронируют свободный слот, потому что в момент проверки он таким и был.

Кликая по демоверсии тихим вторничным днём, невозможно определить, надёжно ли объединены проверка и запись под капотом или же они опасно разделены, — календарь выглядит одинаково в обоих случаях.

Почему "просто добавьте календарь получше" не решает проблему

Под капотом многих систем бронирования скрывается обычный конструктор форм, который никогда не проектировался под ситуацию, когда два человека одновременно претендуют на одну и ту же ограниченную вещь. Выбор даты может быть плавным, доступность — выглядеть живой, экран подтверждения — аккуратным, а бэкенд при этом всё равно проверяет одним чтением и записывает отдельной, более поздней записью. Реальный одновременный трафик находит этот шов.

Модель, которая действительно закрывает разрыв

Перестаньте относиться к «проверке» и «резервированию» как к двум операциям: повторяйте проверку доступности и запись бронирования внутри одной транзакции базы данных, блокирующей строки для этого слота. Какой бы запрос ни пришёл первым, он завершает проверку-и-запись без прерываний; второй ждёт своей очереди, а затем перепроверяет уже новую реальность. Не остаётся окна, в котором можно было бы действовать по устаревшей информации «ещё доступно» — порядок обеспечивает база данных, а не код приложения, надеющийся, что гонки не случится.
Бронирование и расписание в админпанели Olmira

Что на самом деле происходит, когда двое одновременно нажимают «забронировать»

1

Оба запроса приходят почти одновременно

2

Один запрос первым получает блокировку

3

Первый запрос одновременно перепроверяет и записывает

4

Второй запрос заново сверяется с новой реальностью

5

Второй клиент узнаёт об этом сразу

Как это устроено в Olmira

Механизм бронирования Olmira выполняет повторную проверку доступности и запись брони одним шагом, внутри одной заблокированной транзакции базы данных, — поэтому когда два клиента одновременно нацеливаются на один и тот же слот, одна бронь фиксируется, а второму, ещё до того как переместятся какие-либо деньги, сообщается, что время только что заняли. Та же блокировка охватывает и сам ресурс, а не только продаваемую услугу, так что две разные услуги, использующие один кабинет или одного сотрудника, тоже не могут незаметно занять его дважды. Отдельная, более простая защита ловит более частую оплошность — тот же клиент дважды нажимает «забронировать» — и просит его подтвердить, вместо того чтобы молча создать две записи. Как всё это устроено вместе, смотрите на странице бронирования.

Похожие руководства

Персонал, помещения, оборудование

Неявки: что действительно меняет цифру

Календарь, который честно показывает, что свободно

Реальные слоты, проверенные и заблокированные в момент бронирования, — а не догадка по тому, что страница загрузила секунду назад.