Rate limit SMS API: как ограничивать поток без потери сообщений

Rate limit SMS API — это ограничение числа запросов или сообщений за интервал времени. Оно защищает инфраструктуру провайдера, но для клиента становится частью контракта интеграции. Если отправлять быстрее разрешённого, API вернёт ошибку, увеличит задержку или временно заблокирует ключ. Простое повторение всех запросов обычно только усиливает перегрузку.
Ограничитель нужно ставить до вызова провайдера и связывать с очередью SMS-сообщений. Тогда приложение принимает бизнес-события с собственной скоростью, а наружу выпускает их контролируемым потоком.
Какие лимиты встречаются
Провайдер может ограничивать:
- HTTP-запросы в секунду;
- сообщения или сегменты в секунду;
- размер одного пакетного запроса;
- параллельные соединения;
- отдельные Sender ID, маршруты или типы трафика;
- суточный объём или бюджет;
- запросы статуса и другие служебные методы.
Запрос и сообщение — не всегда одно и то же. Один bulk-запрос может содержать сотни получателей, а длинный текст тарифицироваться несколькими сегментами. До проектирования уточните, какую единицу считает лимит.
Ограничение на стороне клиента
Распространённый алгоритм token bucket хранит условные токены. Каждый вызов забирает токен, а запас пополняется с заданной скоростью. Небольшая ёмкость bucket допускает краткий всплеск, но средний поток остаётся в пределах контракта.
Если провайдер разрешает 50 сообщений в секунду, не стоит настраивать ровно 50 без запаса. Сетевые задержки, несколько экземпляров воркера и округление окон могут создать пики. Рабочий лимит делают немного ниже, а фактическую скорость измеряют.
Для нескольких воркеров локальный счётчик в памяти не подходит: каждый процесс решит, что ему доступны все 50. Нужен общий распределённый лимитер либо заранее разделённая квота.
Backpressure вместо бесконечных ретраев
Когда входящий поток превышает пропускную способность, система должна замедлить приём, накопить ограниченную очередь или отказать контролируемо. Это и есть backpressure. Без него очередь растёт до исчерпания памяти или сообщения приходят слишком поздно, чтобы быть полезными.
Для каждой задачи нужен TTL. Код входа через двадцать минут бесполезен, даже если технически может быть отправлен. Просроченную задачу лучше завершить понятным статусом, чем продолжать борьбу за доставку.
Что делать с ответом 429
HTTP 429 означает, что запросов слишком много. Если ответ содержит Retry-After, задержку следует уважать. Если подсказки нет, применяют ограниченное число повторов с экспоненциальной задержкой и случайным jitter, чтобы все воркеры не проснулись одновременно.
Повтор должен сохранять тот же ключ бизнес-операции. Идемпотентность SMS API защищает от дубля, если первый запрос был принят, а ответ оказался неоднозначным. Новый ключ на каждой попытке превращает retry в новую отправку.
Не все ошибки требуют повтора. Неверный номер, запрещённый Sender ID или ошибка шаблона не исчезнут после ожидания. Ретраи оставляют для временных состояний: 429, часть 5xx, сетевой таймаут и явно документированные коды провайдера.
Приоритеты трафика
Единую квоту нельзя отдавать длинной маркетинговой кампании, если через тот же ключ идут OTP и аварийные уведомления. Разделите очереди и зарезервируйте пропускную способность для критичных сценариев. Подробнее эта схема разобрана в материале про приоритеты SMS-трафика.
Справедливое планирование предотвращает и обратную проблему: постоянный поток OTP не должен навсегда остановить допустимые сервисные сообщения. Для классов трафика задают веса, максимальное ожидание и независимые лимиты.
Пакетные запросы
Batch API снижает накладные расходы, но усложняет обработку частичного результата. Нужно знать, принял ли провайдер весь пакет или только часть, и получить идентификатор каждого сообщения. Повтор всего пакета после неопределённого ответа опасен дублями.
Размер пакета выбирают по измерениям. Слишком маленький не использует канал, слишком большой увеличивает время одной операции и объём повторной работы. Учитывайте максимальный размер HTTP-тела и время обработки у провайдера.
Метрики
Минимальный набор наблюдения:
- фактические запросы и сообщения в секунду;
- доля 429 и длительность
Retry-After; - размер и возраст очереди;
- число повторов на сообщение;
- доля задач, истёкших по TTL;
- скорость по классам трафика и ключам;
- время от бизнес-события до принятия SMS API.
Сам по себе низкий процент ошибок не означает здоровье. Если очередь растёт при нуле 429, клиентский лимит может быть слишком консервативным или воркеры не справляются.
Изменение квоты
Повышение лимита у провайдера не гарантирует рост доставки: далее действуют возможности маршрутов и операторов. Перед изменением проведите нагрузочное тестирование SMS без неконтролируемой реальной отправки, затем увеличивайте поток ступенями.
Конфигурацию квот храните централизованно с версией и владельцем. Изменение должно попадать в аудит, потому что ошибка одного числа способна остановить критичный трафик или резко увеличить расходы.
Чек-лист
- известно, что именно считает лимит: запросы, сообщения или сегменты;
- ограничитель общий для всех экземпляров приложения;
- есть запас ниже договорной границы;
- 429 обрабатывается отдельно и учитывает
Retry-After; - ретраи ограничены, используют jitter и сохраняют idempotency key;
- постоянные ошибки не повторяются;
- критичный трафик имеет зарезервированную квоту;
- очередь ограничена по размеру и TTL;
- метрики показывают скорость, возраст очереди и отказы.
Итог
Rate limit — не помеха, которую нужно обойти, а параметр производительности системы. Очередь, общий лимитер, backpressure, приоритеты и безопасные повторы превращают внешнюю квоту в предсказуемый поток. Главное — ограничивать работу до вызова SMS API и измерять не только ошибки, но и время ожидания сообщения.