Как автоматически обрабатывать ошибки SMPP и DLR

Ошибки SMPP показывают, на каком этапе остановилась отправка SMS: шлюз отклонил запрос, сеть временно ограничила скорость или абонент не получил сообщение. В статье разберём коды ESME_RTHROTTLED, ESME_RINVSRCADR и другие ответы, свяжем их с DLR и разделим ошибки на временные и окончательные. После этого разработчик сможет настроить повторы, журналирование и уведомления так, чтобы система не отправляла один и тот же SMS бесконечно.

Что именно сообщает SMPP-ответ?

При передаче submit_sm приложение получает от SMPP-шлюза командный статус. Он отвечает на вопрос, принял ли шлюз запрос в обработку. Успешный ответ ещё не означает, что SMS дошло до телефона: окончательный результат обычно приходит позже в delivery receipt, или DLR.

Удобно разделять два события. SMPP-ответ описывает приём команды шлюзом, а DLR сообщает результат дальнейшей доставки. Если приложение проверяет только submit_sm, оно видит лишь начало цепочки и может ошибочно считать сообщение доставленным.

ЭтапЧто проверятьКакой вывод сделать
Подключениеbind_resp и состояние сессииМожно ли передавать команды через текущую SMPP-сессию
Приём сообщенияcommand_status в submit_sm_respПринял ли шлюз запрос и выдал ли message_id
ДоставкаDLR и его delivery statusДошло ли SMS до абонента или оператор вернул отказ
Контроль каналаenquire_link, тайм-ауты, disconnectЖива ли сессия и можно ли продолжать отправку

При разборе DLR полезно сохранять исходный текст receipt, message_id, время отправки и внутренний идентификатор операции. Без этой связи трудно понять, какой именно запрос завершился ошибкой, особенно когда система отправляет большой поток SMS.

Почему возникает ESME_RTHROTTLED?

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

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

  1. Получить ответ ESME_RTHROTTLED.
  2. Вернуть сообщение в очередь с новым временем попытки.
  3. Увеличить задержку по выбранной схеме.
  4. После установленного числа неудач передать событие в журнал или мониторинг.

Один worker не должен бесконтрольно создавать новые потоки при ограничении скорости. Надёжнее использовать общий планировщик очереди: он видит число активных запросов и равномерно распределяет отправку между доступными SMPP-сессиями.

Параметры TON и NPI тоже влияют на принятие сообщения. Если проблема связана с адресацией отправителя или получателя в белорусском направлении, проверьте настройку TON/NPI в SMPP для SMS в Беларуси, а не увеличивайте количество повторов.

Как исправить ESME_RINVSRCADR?

ESME_RINVSRCADR сообщает, что адрес источника некорректен или не разрешён для этого подключения. Причина часто связана с полем source_addr: приложение передало значение в неподходящем формате, использовало неверный TON/NPI или выбрало отправителя, которого шлюз не принимает.

Такой отказ обычно относится к окончательным для конкретного запроса. Повтор с теми же параметрами результата не изменит. Сначала нужно исправить данные отправителя, проверить разрешённый формат и только потом создать новую попытку.

В конфигурации полезно хранить отправителя отдельно от текста SMS. Перед отправкой приложение проверяет, что значение заполнено, соответствует выбранному типу адреса и доступно этому SMPP-аккаунту. Ошибка должна попадать в журнал вместе с source_addr, TON, NPI и идентификатором маршрута.

СитуацияДействие приложенияНужен повтор?
ESME_RTHROTTLEDПауза, возврат в очередь, ограничение скоростиДа, с задержкой
ESME_RINVSRCADRОстановить запрос, проверить source_addr и TON/NPIНет, пока параметры не исправлены
Недействительная сессияЗакрыть соединение и выполнить повторный bindДа, после восстановления канала
Отказ доставки в DLRСохранить финальный статус и причинуТолько по отдельному правилу для временных причин

Как строить обработчик SMPP-ошибок?

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

Минимальная запись в очереди может содержать message_id, номер получателя, текст или его ссылку, время следующей попытки, число повторов и последний код ошибки. Текст SMS не стоит менять при каждом повторе: иначе DLR и внутренний журнал будет сложнее сопоставить.

Для временных ошибок используйте отложенную очередь. Для окончательных отказов сразу фиксируйте результат и не возвращайте сообщение в обычный поток. Отдельный статус «требует проверки» пригодится для неизвестных кодов: приложение не потеряет событие и не начнёт бесконечный цикл.

При большом объёме трафика проверьте обработчик в тестовой среде. SMPP-песочница для проверки SMS, DLR и конкатенации помогает отделить ошибку бизнес-логики от особенностей реального маршрута. Для OTP отдельно проверьте повторы и связь результата с кодом подтверждения: полезен материал о передаче OTP-кода через SMPP с DLR и повторами.

Какие данные записывать в журнал?

  • время отправки и время получения ответа;
  • тип SMPP-команды и command_status;
  • message_id, если шлюз его вернул;
  • source_addr, TON и NPI;
  • номер получателя в нормализованном формате;
  • текст или безопасный идентификатор шаблона;
  • DLR и финальный статус доставки;
  • номер попытки и причина следующего повтора.

Логи должны позволять найти одну операцию по message_id и внутреннему идентификатору заказа. Если в журнале есть только общий текст «SMS не отправлено», разработчик не отличит ограничение скорости от неверного адреса отправителя.

Какие ошибки чаще всего ломают автоматическую отправку?

  • Приложение считает успешный submit_sm_resp доказательством доставки.
  • ESME_RTHROTTLED повторяется без паузы и перегружает очередь.
  • ESME_RINVSRCADR отправляется повторно с тем же source_addr.
  • Программа теряет message_id и не может связать DLR с исходным SMS.
  • Неизвестный код автоматически трактуется как временный, поэтому очередь растёт бесконечно.
  • После разрыва соединения приложение повторяет запрос, не проверив состояние сессии и риск дубликата.

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

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

  1. Составьте таблицу кодов с колонками «временная ошибка», «повтор», «максимум попыток» и «действие после отказа».
  2. Свяжите submit_sm_resp, message_id и DLR в одном журнале операций.
  3. Прогоните тесты для ESME_RTHROTTLED и ESME_RINVSRCADR, чтобы система ставила паузу в первом случае и исправляла параметры во втором.