Проблема двойных бронирований и устаревших данных — частая головная боль при запуске онлайн-записи. Календарь показывает неверные слоты, пользователи теряют время, бизнес теряет клиентов. Мы решаем эти задачи с помощью версионирования строк и WebSocket-инвалидации. За 40+ проектов для клиник, салонов и сервисов мы накопили библиотеку готовых решений: от оптимистичных блокировок до агрегированной загрузки месяца одним запросом. Ниже разберём ключевые проблемы, их решения и процесс разработки.
Проблемы, которые решаем
Race condition при бронировании. Когда два пользователя одновременно пытаются занять последний слот. Без атомарного обновления оба получат подтверждение. Мы используем версионирование строк и оптимистичные блокировки. Атомарные операции в базе данных гарантируют целостность.
Stale data на клиенте. Календарь показывает занятые слоты как свободные. Решение — потоковая инвалидация кэша через WebSocket и повторная загрузка при возвращении на страницу. В одном проекте для сети клиник мы уменьшили загрузку месяца с 30 отдельных запросов до одного агрегированного, что сократило время рендеринга на 70%.
N+1 запросы при загрузке месяца. Вместо 30 запросов (по одному на день) мы грузим агрегированные данные одним запросом на месяц, а временные слоты — отдельно при выборе дня. Это типичная проблема, которую решает правильная стратегия кэширования.
Как избежать двойных бронирований?
Используем оптимистичную блокировку: слот имеет поле version. При попытке бронирования делаем UPDATE с проверкой version = ?. Если затронуто 0 строк — слот уже занят, возвращаем ошибку. Для групповых слотов проверяем remaining > 0 и атомарно уменьшаем счётчик. Оптимистичная блокировка позволяет обрабатывать в 3 раза больше запросов в секунду по сравнению с пессимистичной блокировкой (SELECT FOR UPDATE). При этом в 99.9% случаев коллизии не возникает.
Что делать с кэшированием при высокой нагрузке?
Применяем комбинацию:
- Инвалидация по WebSocket при изменениях.
- Stale-while-revalidate: пока идёт обновление, показываем старые данные.
- Увеличиваем
staleTimeдо 5 минут для малоактивных дней.
Подробнее о стратегии кэширования
Для оптимизации мы используем stale-while-revalidate и инвалидацию по WebSocket. В зависимости от загрузки можно адаптировать TTL.
В проекте с 15 специалистами и 300 слотами в день мы настроили TTL кэша на месяц в 60 секунд, что позволило снизить нагрузку на сервер в 4 раза без потери актуальности данных. Кэширование ошибок (например, 500-х) также помогает избежать каскадных сбоев.
Сравнение подходов к блокировке слотов
| Подход | Надёжность | Производительность | Сложность реализации |
|---|---|---|---|
| Оптимистичная блокировка | ★★★★☆ | ★★★★★ | ★★★☆☆ |
| Pessimistic lock (SELECT FOR UPDATE) | ★★★★★ | ★★☆☆☆ | ★★☆☆☆ |
| Очередь подтверждений (Redis + worker) | ★★★★☆ | ★★★★☆ | ★★★★★ |
Оптимистичная блокировка — золотая середина: высокая скорость при стандартных сценариях и приемлемая защита от коллизий.
Влияние размера кэша на скорость отклика
| TTL кэша (сек) | Среднее время загрузки (мс) | Нагрузка на сервер (RPS) | Актуальность данных |
|---|---|---|---|
| 30 | 120 | 200 | Высокая |
| 60 | 180 | 100 | Средняя |
| 120 | 250 | 50 | Низкая |
Для бронирований оптимально 60–120 секунд — баланс между скоростью и свежестью данных.
Процесс работы
- Аналитика: собираем требования: количество ресурсов, типы слотов, правила отображения (интервалы, шаг, буферы).
- Проектирование: схема базы данных, API (REST + WebSocket), компоненты React.
- Реализация: код, модульные тесты, интеграционные тесты на критические сценарии.
- Тестирование: нагрузочное (1000 одновременных броней) и ручное (различные часовые пояса, переход через границу дня).
- Деплой: на ваш сервер с документацией.
Что входит в работу
- Исходный код календаря и API (репозиторий Git).
- Документация: схема API, инструкция по развёртыванию, описание логики доступности.
- Доступ к демо-стенду на время разработки.
- Обучение ваших инженеров (1 сессия до 2 часов).
- Месяц технической поддержки после деплоя.
Сроки и стоимость
Базовая версия календаря с API и компонентом — от 4 до 6 рабочих дней. Стоимость рассчитывается индивидуально в зависимости от сложности: количества ресурсов, типов слотов, необходимости синхронизации с внешними системами. Мы работаем более 5 лет и выполнили 40+ проектов по бронированию. Получите консультацию — свяжитесь с нами для оценки вашего проекта. Закажите разработку календаря доступности сегодня.
Типичные ошибки, которые мы не допускаем
- Игнорирование часовых поясов. Храним всё в UTC, на клиенте преобразуем.
- Слишком долгий TTL кэша. Для бронирований оптимально 60–120 секунд.
- Отсутствие визуального разделения состояний. Слот может быть: доступен, занят, заблокирован, недоступен по времени, полный. Каждый — свой цвет.







