Как избежать дублей SMS при повторной отправке событий

Как избежать дублей SMS при повторной отправке событий

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

Почему клиент получает два одинаковых SMS?

Чаще всего виновата не злая воля, а технический сбой или неаккуратная ручная отправка. Менеджер дважды нажал кнопку «Отправить», CRM повторно отправила вебхук, скрипт перезапустился после ошибки — и событие ушло в шлюз ещё раз. Иногда повторный запрос приходит из-за таймаута: система не получила подтверждение от оператора и решила, что сообщение потеряно, а оно уже доставлено.

В Беларуси к этому добавляются особенности доставки: сообщение может идти дольше обычного, а ответ от оператора — приходить с задержкой. Если ваша система настроена на «переотправку по таймауту», дубль почти гарантирован. Подробнее о том, почему уведомления задерживаются, мы разбирали в отдельном материале о статусах заказов в Беларуси.

Что такое идемпотентность и как она помогает?

Идемпотентность — это свойство операции, при котором повторное выполнение даёт тот же результат, что и первое. Применительно к SMS это значит: какое бы количество раз ни пришло событие, клиент получит только одно сообщение.

Технически это реализуется через уникальный ключ. Например, для уведомления о смене статуса заказа ключом будет связка «номер заказа + новый статус». Для оплаты — «номер платежа». Перед отправкой система проверяет, отправляла ли она уже сообщение с таким ключом. Отправляла — пропускает. Нет — отправляет и сохраняет ключ в базу или кэш.

Ключ не должен быть просто номером телефона: с одного номера у вас много разных событий, и все они будут ошибочно приняты за одно. Нужна именно комбинация, которая однозначно определяет событие.

Чек-лист: как настроить защиту от дублей

  1. Добавьте в таблицу отправленных SMS поле unique_key — строку вида order_12345_shipped или payment_9876.
  2. Перед вызовом SMS-шлюза проверяйте, существует ли уже запись с таким ключом.
  3. Отправляйте сообщение и только после успешного ответа оператора записывайте ключ.
  4. Если ответа нет — не отправляйте повторно автоматически. Поместите запись в очередь на ручную проверку. Альтернатива — настроить переотправку с проверкой статуса предыдущего сообщения через API.
  5. Ведите журнал всех попыток с указанием ключа, времени и результата. Это поможет быстро найти источник сбоя.

Если вы используете готовую платформу (CRM, скрипт интернет-магазина), проверьте, есть ли в ней встроенный механизм идемпотентности. У многих популярных решений он уже есть, но бывает выключен по умолчанию. Включите его и укажите, какое поле считать ключом события.

Сравнение подходов: база данных vs кэш

КритерийБаза данныхКэш (Redis, Memcached)
НадёжностьВысокая, данные не теряютсяСредняя, при перезапуске кэш может очиститься
СкоростьНиже на больших объёмахВысокая
Простота внедренияПодойдёт для малого бизнеса, нет лишних зависимостейТребуется отдельный сервис кэширования
Срок храненияДолгий, можно хранить как архивОграничен настройками TTL

Для интернет-магазина с 30–50 заказами в день хватит обычной таблицы в базе данных. Кэш имеет смысл, если у вас тысячи событий в час и вы упираетесь в производительность.

Типичные ошибки при защите от дублей

  • Использовать только номер телефона как ключ. Это блокирует все последующие уведомления после первого. Ключ обязан включать идентификатор события.
  • Проверять ключ после вызова шлюза. Если ответ пришёл, но запись не сохранилась из-за сбоя, следующий запрос уйдёт повторно.
  • Переотправлять при таймауте без проверки. Лучше подождать и запросить статус через API, чем отправить второе SMS.
  • Игнорировать распределённые системы. Если у вас два сервера обрабатывают события, нужна блокировка или транзакция, иначе оба пройдут проверку одновременно.
  • Не чистить старые ключи. База растёт, но это не страшно. Главное — не забудьте про индекс по полю unique_key, иначе проверка станет медленной.

Как проверить, что защита работает

Создайте тестовый заказ с заведомо повторным событием. Отправьте одно и то же уведомление дважды с интервалом в несколько секунд. Если во втором случае система не отправила SMS — всё настроено правильно.

Также проверьте сценарий, когда от SMS-шлюза не приходит ответ. Запустите отправку, прервите соединение до получения подтверждения, затем повторите попытку. Ваша система должна либо запросить статус, либо отправить сообщение с тем же ключом — и оно должно быть заблокировано.

Если клиент жалуется на пропажу уведомлений, а не на дубли — есть смысл отдельно разобрать как проверить недоставку SMS и что делать в этом случае. Дубли и потери часто соседствуют: одна ошибка может вызывать и то, и другое.

Для более глубокого понимания причин, по которым SMS вообще не доходят до абонента, посмотрите чек-лист по проблемам доставки — он поможет отделить проблему дублей от системных сбоев канала.

3 шага, которые можно сделать сегодня:

  1. Добавьте поле unique_key в таблицу отправленных сообщений и проставьте индекс.
  2. Внедрите проверку ключа перед каждым вызовом SMS-шлюза.
  3. Настройте журнал всех попыток с ключами и результатами — так вы увидите дубли ещё до того, как они дойдут до клиента.