Как настроить graceful degradation SMS-рассылки при превышении лимитов оператора

Как настроить graceful degradation SMS-рассылки при превышении лимитов оператора

SMPP-провайдеры по умолчанию держат жёсткий потолок по скорости — 30 SMS в секунду (Vonage). Если в пик рассылка упирается в этот лимит, SMSC отвечает кодом 0x00000058 (Throttling error, десятиричное значение 88) и просто отбрасывает сообщение. Решение — graceful degradation: вместо бинарного «отправил/не отправил» система сама снижает скорость, переключает канал или складывает сообщения в очередь. В статье — практический сценарий, как собрать такую логику на стороне клиента без дорогих анализаторов и без потери сообщений.

Почему операторы вообще вводят лимиты и откуда берётся код 88

Каждый SMSC защищает собственные ресурсы: транзакции, базы пользователей, маршрутизаторы. У SMPP-аккаунта есть «потолок» — он называется TPS, transactions per second, сделки в секунду. По умолчанию у большинства провайдеров это 10–30 SMS в секунду, и цифра зависит от тарифа (Vonage, SMPP Center).

Когда клиент отправляет больше, SMSC возвращает NACK с кодом Throttling error. Сообщение теряется на стороне клиента, если тот не повторит попытку. Параллельно у SMSC есть ещё один лимит — число неподтверждённых PDU, которые клиент держит в окне (window size). Если поднимать TPS, не трогая размер окна, число ошибок только растёт (SMSGatewayCenter).

Что должна делать система при первом throttle-ответе

Главное — не паниковать и не выкидывать сообщение. Сценарий graceful degradation строится на трёх реакциях: пауза, повтор, откат на резервный канал.

  • Пауза. Получили NACK с кодом 88 — ставим экспоненциальную задержку перед следующим submit_sm. Стартовая пауза 100 мс, удвоение при каждом повторе до потолка в 5 секунд.
  • Повтор. Помечаем сообщение флагом retry_count, отправляем снова, но не больше трёх попыток. После трёх NACK переводим в dead-letter queue.
  • Откат. Если retries исчерпаны и TPS не падает — переключаемся на резервный канал или снижаем скорость до 50% от текущей. Снижение делаем постепенно, чтобы не устроить «качели» между throttle и нормальной работой.

Как выбрать окно и TPS, чтобы не упереться в лимит

Перед настройкой важно понять, что именно сейчас узкое место. Их три, и путать их — самая частая ошибка (SMSGatewayCenter):

ПараметрЧто ограничиваетТипичный дефолт
TPS аккаунтаСкорость отправки, которую разрешил провайдер10–30 SMS/с
Window sizeЧисло неподтверждённых submit_sm в очередиЗадаётся в bind_transceiver
Downstream capacityПотолок SMSC по конкретному маршруту в пиковые часыНиже TPS аккаунта

Если видите серию throttle-ошибок при умеренной нагрузке — проверьте, не упираетесь ли в downstream. Поднять window size, когда узкое место TPS аккаунта, бесполезно: получите больше ошибок, а не больше доставок.

Как собрать очередь с приоритетами, а не «всё в одну кучу»

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

Минимальный набор очередей:

  • High. OTP, пароли, уведомления по статусу заказа. Жёсткий SLA в секундах.
  • Medium. Сервисные уведомления — доставка, баланс, изменение тарифа.
  • Low. Маркетинговые кампании. Отправляются, когда есть запас по TPS, остаток — в очередь следующего окна.

Если приоритетная очередь занимает больше 80% доступного TPS, маркетинговая автоматически встаёт на паузу. Это и есть graceful degradation: ничего не теряется, просто меняется порядок и скорость.

Зачем нужен enquire_link и какие паузы реально опасны

Параллельно с throttling у SMPP есть второй тихий враг — inactivity timeout. Сервер закрывает сессию, если за 120 секунд не пришёл ни один PDU, включая enquire_link (Mobile Text Alerts). Без keepalive клиент теряет соединение и долго восстанавливает его в пик нагрузки.

Рабочий диапазон — отправлять enquire_link каждые 30–60 секунд. Если соединение рвётся чаще, чем раз в час, проверьте сетевой путь и таймауты на firewall: NAT любят «забывать» неактивные TCP-сессии.

Типичные ошибки, которые ломают graceful degradation

  • Сразу резать TPS в ноль при первом throttle-ответе. Сеть «качается», и через минуту вы уже недоиспользуете канал.
  • Хранить очередь только в памяти процесса. При рестарте контейнера сообщения исчезают, и клиент думает, что они доставлены.
  • Игнорировать разницу между Throttling error и просто ошибкой маршрутизации. Код 0x00000058 лечится паузой, остальные — нет.
  • Забывать про enquire_link во время длительной паузы. SMSC закрывает сессию, а выясняется это только по следующей submit_sm.
  • Повышать window size, не проверив TPS аккаунта. Получаете больше throttle-ответов и больше нагрузки на собственный retry-loop.

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

  1. Поднять в логах отметку по коду 0x00000058 и собрать статистику — в какие часы и на каких маршрутах он срабатывает чаще.
  2. Внедрить очередь с приоритетами и экспоненциальную паузу на retry, чтобы маркетинг не вытеснял транзакционные сообщения.
  3. Настроить enquire_link каждые 30–60 секунд и проверить таймауты на NAT — иначе пауза сама убьёт соединение.
Полезные ссылки failover между SMPP-провайдерами, отказоустойчивая отправка транзакционных SMS, TLS для SMPP, RocketSMS как пример SMPP-шлюза с уже встроенной защитой от throttle.