Как обрабатывать submit_sm_resp в SMPP и не создавать дубли

Как обрабатывать submit_sm_resp в SMPP и не создавать дубли

Ответ submit_sm_resp показывает, принял ли SMPP-сервер запрос на отправку SMS. Чтобы обработать его корректно, проверьте command_status, сохраните message_id при успешном ответе и разделите ошибки на повторяемые и постоянные. Если ответ не пришёл вовремя, результат отправки остаётся неизвестным: повторный запрос может создать дубль. Ниже — порядок обработки ответа, правила повторных попыток и способ связать каждую отправку с записью в вашей системе.

Что проверять в submit_sm_resp?

После отправки submit_sm клиент получает submit_sm_resp. Сначала проверьте command_status: нулевое значение означает, что сервер принял запрос. Это подтверждает приём сообщения шлюзом, но само по себе не доказывает доставку на телефон.

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

Если command_status указывает на ошибку, запишите значение статуса, время ответа и идентификатор исходной операции. Так можно отличить отказ сервера от ситуации, когда запрос вообще не дошёл до ответа. Для поиска проблем храните журнал отправки отдельно от текста SMS, если полный текст не нужен для диагностики.

Какие ошибки повторять?

Не запускайте повторную отправку при любой ошибке без разбора. Сначала определите, относится ли отказ к временным условиям или к самому запросу. Временная ошибка допускает повтор после паузы; постоянная требует исправить запрос или данные получателя.

  • При временном отказе поставьте сообщение в очередь повторов и задайте паузу перед следующей попыткой.
  • При ошибке параметров или формата остановите повторы, сохраните причину и отправьте запись на исправление.
  • При ограничении пропускной способности уменьшите темп отправки и проверьте настройки потока; подробности — в материале об ошибках пропускной способности submit_sm.
  • При потере соединения или таймауте пометьте результат как неизвестный, а не как отказ: сервер мог принять сообщение, но ответ не дошёл до клиента.

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

Как защититься от дублей при таймауте?

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

Создайте в своей системе уникальный ключ отправки, например идентификатор события заказа или уведомления. Перед отправкой сохраните запись со статусом «в обработке». При повторном запуске сначала проверьте этот ключ: если операция уже получила успешный ответ, второй submit_sm не отправляйте.

После таймаута оставьте запись в неопределённом состоянии и выполните сверку по доступным данным шлюза. Если выяснить результат нельзя, решение о повторе принимайте по важности сообщения и риску дубля. Для сценариев, где повторное SMS заметно пользователю, правила такой обработки нужно согласовать с логикой приложения. Дополнительные варианты защиты описаны в материале о защите API и SMPP от повторной отправки SMS.

Как организовать обработку ответа в приложении?

Разделите отправку и обработку ответа на понятные состояния. Например: «создано», «отправляется», «принято шлюзом», «ошибка», «результат неизвестен». Состояние «принято шлюзом» устанавливайте только после успешного submit_sm_resp. Отчёт о доставке обрабатывайте отдельно, если подключён приём таких отчётов.

  1. Создайте запись отправки с уникальным внутренним ключом.
  2. Отправьте submit_sm и дождитесь submit_sm_resp в пределах настроенного таймаута.
  3. При успехе сохраните command_status и message_id; при ошибке запишите статус и выберите действие по типу ошибки.
  4. При таймауте не считайте сообщение отклонённым: пометьте результат неизвестным и исключите слепой повтор.

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

Начните с короткой проверки: найдите в журнале одну отправку и проследите её путь от внутреннего ключа до submit_sm_resp. Убедитесь, что при таймауте система не отправляет запрос повторно автоматически.