CRM-аналитика
Два сценария отправляют одновременно: как разрешить гонку за частотный лимит
Время чтения: 5 мин
Уровень материала: Для экспертов
Содержание
У клиента остался один разрешённый рекламный контакт на сегодня. В одну секунду запускаются письмо о снижении цены и сообщение о брошенной корзине. Оба сценария видят свободный лимит и оба отправляют сообщение. В каждой цепочке проверка есть, но общая политика всё равно нарушена.
Это гонка: результат зависит от того, как совпали во времени независимые операции. Частотный лимит ограничивает число сообщений одному клиенту за определённый период. Если проверка остатка и занятие места выполняются отдельно, два процесса могут использовать один и тот же остаток.
Сначала определите единицу ограничения
Лимит должен иметь точную область: клиент или контакт, бренд или группа брендов, канал или все каналы, календарный день или скользящие 24 часа. Также нужно определить, что расходует его: решение отправить, приём сообщения провайдером или подтверждённая доставка.
У разных платформ определения отличаются. Например, Braze описывает частотные правила по каналам и тегам и собственный порядок их применения. Перенос числа «три» из одной платформы в другую без переноса смысла счётчика не сохраняет политику.[1]
Для распределённой системы практично считать подтверждённые попытки по согласованному событию и отдельно учитывать незавершённые резервы. Выбранное правило должно быть понятно бизнесу: иначе технически правильная реализация даст неожиданное число сообщений.
Объедините проверку и резервирование
Резервирование — временное занятие одного доступного места перед отправкой. Проверить остаток и создать резерв нужно как одну неделимую операцию. Тогда второй сценарий увидит уже занятое место.
В базах данных такое поведение обеспечивают выбранной схемой блокировок, условным обновлением или подходящим уровнем изоляции. Документация PostgreSQL показывает, почему отдельные чтения при обычной изоляции не заменяют управление конкурентными изменениями; сериализуемые операции могут требовать повтора после конфликта.[2]
Это инженерная задача, а не настройка дополнительной задержки на пять секунд. Задержка уменьшает вероятность совпадения, но не доказывает соблюдение лимита.
Опишите жизненный цикл места
Предлагаемая модель CRM Lab различает свободное место, резерв, подтверждённый расход и неопределённый результат. У резерва есть идентификатор запроса, сценарий, момент создания и условия освобождения.
| Событие | Что сделать с лимитом | Почему |
|---|---|---|
| Резерв создан, отправка ещё не началась | Считать место занятым | Другой процесс не должен использовать его |
| Провайдер однозначно отказал до приёма | Освободить по согласованному правилу | Подтверждённой попытки не произошло |
| Провайдер подтвердил приём | Зафиксировать расход | Отправка уже вышла из локального контроля |
| Ответ потерян после запроса | Сохранить неопределённое состояние и сверить | Сообщение могло быть принято |
| Процесс умер до обращения к провайдеру | Освободить после подтверждения безопасного истечения | Нельзя навсегда терять место |
Истечение времени резерва не должно автоматически разрешать повтор, если результат передачи неизвестен. Иначе медленный ответ создаст два сообщения вместо одного. Здесь нужна сверка по идентификатору и защита от повторного исполнения.
Разделите приоритет и соблюдение лимита
Атомарный резерв гарантирует, что место займёт один процесс. Он не гарантирует, что победит более ценный сценарий: первым может успеть любой. Если бизнесу нужен приоритет, кандидатов необходимо выбирать по отдельному правилу до необратимой отправки.
Можно собирать предложения в коротком окне, ранжировать их или выделять квоты по классам сообщений. Каждый вариант имеет цену задержки и сложности. Для срочного запроса клиента ожидание общего окна может быть неприемлемо, поэтому назначение сообщений рассматривают заранее.
Коммуникационная политика должна объяснять и судьбу проигравшего сценария. Его можно отменить или пересмотреть позже, но нельзя бесконечно переносить устаревшее предложение до первого свободного места.
Условный пример: один слот, два кандидата
Лимит — одно рекламное сообщение за скользящие 24 часа. В 14:00 два сценария запрашивают место. Сервис принимает заявку корзины и отклоняет снижение цены. Затем заказ уже оформлен, и последняя проверка останавливает корзину до передачи провайдеру.
Резерв освобождается, но снижение цены не должно автоматически отправляться по старому решению. Сначала заново проверяются актуальность предложения, состояние клиента, разрешение и оставшийся срок. Освобождённый лимит — только одно из условий допуска.
Какие испытания обязательны
Запустите много одновременных запросов на один тестовый профиль и проверьте число фактических передач. Повторите тот же идентификатор запроса, прервите процесс до и после обращения к провайдеру, задержите ответ и восстановите сервис.
Отдельно проверьте границу окна, смену даты, объединение профилей и два канала. Условия до отправки должны работать вместе с лимитом, а не обходить его отдельной кнопкой массового запуска.
Результат проверки выражается просто: допустимое число действий не превышено, повтор не создаёт новую отправку, неопределённый результат не превращается в свободное место без сверки. Это надёжнее, чем два правильных флажка в независимых сценариях.
Источники
[1] Braze. Rate limiting and frequency capping. Messaging Fundamentals, документация Braze. Проверено 22.09.2026.
[2] PostgreSQL Global Development Group. Transaction Isolation. PostgreSQL Documentation, раздел 13.2. Проверено 22.09.2026.