Ретраи и сбои
Если приёмник не ответил 2xx, доставка повторяется по фиксированному расписанию. Если он не отвечает почти сутки — вебхук отключается, а владельцу уходит письмо.
Расписание повторов
| Попытка | Когда |
|---|---|
| 1 | сразу после события |
| 2 | +5 секунд |
| 3 | +5 минут |
| 4 | +30 минут |
| 5 | +2 часа |
| 6 | +5 часов |
| 7 | +10 часов |
| 8 | +10 часов |
Всего 8 попыток за ~28 часов. К каждой паузе добавляется случайный джиттер ±10 %: без него тысяча событий одной транзакции била бы в ваш сервер синхронно — ровно в тот момент, когда он и так лежит.
Диспетчер просыпается раз в минуту. Одиночное изменение доезжает в пределах минуты, массовая операция (применение черновика, удаление сотрудника навсегда) — пачкой, в пределах ~15 минут: за один заход в очередь с одного эндпоинта берётся не больше 50 доставок, чтобы один шумный приёмник не занял всю партию. Заходов в минутном тике несколько — партия за партией, пока хватает бюджета тика (50 секунд).
Номер текущей попытки виден в заголовке Smengo-Delivery-Id — после двоеточия.
Классификация ответа
| Ответ приёмника | Что делаем |
|---|---|
2xx |
успех, тело ответа игнорируется |
3xx |
провал redirect_not_allowed: редиректы не переходим — адрес должен обслуживаться конечным сервером |
410 Gone |
терминально: доставка помечается мёртвой, эндпоинт сразу отключается |
429, 5xx |
провал с повтором; учитывается заголовок Retry-After |
прочие 4xx |
провал с повтором |
| нет ответа за 15 секунд | провал timeout с повтором |
| сеть, TLS, DNS | провал с повтором (network_…, dns_failed) |
| адрес резолвится в приватную сеть | провал private_address — запрос не отправляется вовсе |
Retry-After
Заголовок понимается в обеих формах RFC 9110 — секунды и HTTP-дата — и применяется как max(расписание, Retry-After) с капом в 1 час. Два следствия:
- сервер может отложить следующую попытку, но не может ускорить её:
Retry-After: 0не превращает ретраи в горячий цикл; - дальше часа отложить нельзя — иначе исчерпание попыток растянулось бы на недели.
Авто-отключение
Триггер — первая доставка, исчерпавшая все 8 попыток (или ответ 410 Gone). Тогда:
- Эндпоинт переводится в состояние «отключён» — доставки прекращаются.
- Все накопившиеся доставки этого эндпоинта помечаются мёртвыми и не будут отправлены после включения: иначе на починенный сервер обрушился бы 28-часовой бэклог.
- Владельцу уходит письмо (на платёжный адрес организации, иначе — на адрес создателя эндпоинта).
- В карточке вебхука появляется баннер с причиной — он виден и без письма.
Как вернуть доставку: почините приёмник → «Отправить тестовое» → убедитесь, что пришёл 2xx → включите вебхук обратно. Пропущенное за время отключения дочитывается через API v1 — ручного повтора доставок в v1 нет.
Пауза, а не отключение
Кнопка «Пауза» — не то же самое, что авто-отключение:
- пока вебхук на паузе, новые события в очередь не попадают вовсе — после возобновления вы получите только то, что произойдёт дальше;
- доставки, уже стоявшие в очереди на момент паузы, уедут после возобновления;
- тестовое событие можно отправить и на паузе — это штатный способ проверить починку.
Неактивная подписка
Если у организации кончился триал и подписка неактивна, push останавливается вместе с остальным платным функционалом: доставка откладывается на час и повторяется, попытка при этом не расходуется, эндпоинт не отключается. После оплаты доставки возобновятся сами, в пределах часа. В журнале такие строки помечены subscription_inactive.
Журнал доставок
- Хранится 30 дней, вместе с телом события — ровно тем, что ушло на ваш адрес.
- Ниже карточек, в блоке «Последние доставки», видны 25 последних доставок по всем вебхукам организации: время, тип события, код ответа, число попыток, тело и история попыток. Лимит общий: при трёх эндпоинтах это 25 строк на всех, а не по 25 на каждый.
- Из ответа сохраняются первые 512 байт — этого достаточно, чтобы увидеть текст ошибки вашего сервера.
Коды в колонке «ошибка»
| Код | Значение |
|---|---|
http_<код> |
сервер ответил не-2xx (например, http_500) |
redirect_not_allowed |
ответ 3xx; редиректы не поддерживаются |
gone |
ответ 410; эндпоинт отключён |
timeout |
ответа не было 15 секунд |
network_<код> |
сетевая ошибка Node (network_ECONNREFUSED, network_EPROTO, …) |
dns_failed |
имя хоста не разрешилось за отведённое время |
private_address |
адрес резолвится в приватный или служебный диапазон |
not_https, port_not_allowed, userinfo_not_allowed, fragment_not_allowed, invalid_url, url_too_long, url_too_short |
адрес не прошёл проверку формы перед отправкой |
subscription_inactive |
подписка организации неактивна, доставка отложена на час |
endpoint_disabled |
доставка погашена при авто-отключении эндпоинта |
lease_expired |
доставка зависла (сбой инвокации) и была подобрана служебным процессом |
Как не попасть на ретраи
- Отвечайте
2xxдо тяжёлой работы: примите событие, проверьте подпись, положите в очередь, ответьте200. - Не отвечайте
3xx: балансировщик, который редиректитhttp→httpsили/hook→/hook/, ломает доставку. Указывайте конечный адрес. - Возвращайте
410только когда адрес мёртв окончательно: этот код отключает вебхук с первого раза. - При временной перегрузке отвечайте
429или503сRetry-After— так вы управляете темпом, не теряя событий.
Что дальше
- Обзор — формат доставки и требования к приёмнику.
- Проверка подписи — готовые примеры на Node и Python.