Идемпотентность¶
Страница для интегратора: как повторять запросы так, чтобы абонент не получил два одинаковых сообщения.
Зачем¶
Сеть рвётся посреди запроса. Клиент не знает, дошёл ли он: ответа нет, а сообщение могло уйти. Повтор без защиты — второе сообщение живому человеку; отказ от повтора — код, который абонент так и не получил.
Idempotency-Key снимает выбор: повтор с тем же ключом возвращает тот же
ответ, что получил первый запрос, и второго сообщения не создаёт.
Как пользоваться¶
Заголовок Idempotency-Key принимается на любом POST API: отправка и
пакет, оценка стоимости, шаблоны и их предпросмотр, подписки на вебхуки (создание,
включение, ротация секрета, пробная доставка). На GET и прочих методах он
игнорируется. Главное — отправка: POST /v1/messages и POST /v1/messages/batch.
Значение — любая строка до 255 символов; UUID удобен, но не обязателен.
Длиннее — 422 idempotency_key_reused с param: Idempotency-Key (ключ не
обрезается: обрезанный склеил бы два разных запроса). Ключ свой на каждую
попытку отправки, а не на сообщение и не на сессию. Повтор из-за обрыва идёт с
тем же ключом; новая отправка — с новым.
Ключи раздельны по аккаунту и режиму (live/test): один и тот же ключ на
боевом и тестовом ключе — два разных запроса. В отпечаток запроса входят метод,
путь и тело: тот же ключ на другой ручке — это 422 idempotency_key_reused,
как и на другое тело.
POST /v1/messages
Idempotency-Key: 0f3c9b21-1c4b-4f6a-9a8f-1b2c3d4e5f60
Ключ живёт 24 часа. Дальше он забывается, и запрос с ним выполнится заново.
Что отвечает хаб¶
| Ситуация | Ответ |
|---|---|
| Первый запрос | обычный 202 с объектом сообщения |
| Повтор, то же тело | тот же ответ, заголовок Idempotent-Replayed: true |
| Повтор, другое тело | 422 idempotency_key_reused — ключ уже занят другим запросом |
| Первый запрос ещё выполняется | 409 idempotency_conflict с retry_after |
Аренда ключа — минута. Если процесс, выполнявший первый запрос, умер, ключ освободится сам, и повтор пройдёт как первый.
Что повторять с тем же ключом¶
429(превышен темп, суточный предел хаба, слишком много неудачных входов) — да, с тем же ключом: такие ответы к ключу не приколачиваются;5xx— да, с тем же ключом: наша неисправность не должна занимать ключ на сутки. Ключ освобождается сразу, и повтор не упрётся в409; если освободить его не удалось (редкий случай — отказ самого хранилища), повтор до конца аренды — не больше минуты — получит409сretry_after. Сюда же относится503 provider_unavailableна одноразовый код — он не принят, и повтор с тем же ключом и тем жеclient_refпримет его заново;409 idempotency_conflict— да, послеretry_after;422— нет. Запрос понятен и невыполним; повтор того же даст то же. Исправьте то, на что указываетcode, и отправьте с новым ключом.
Пакеты¶
У пакета своя защита — client_ref на каждом элементе. Он обязателен: без него
результат элемента не с чем сопоставить, а повтор пакета перестаёт быть
безопасным.
Повтор пакета с теми же client_ref не создаёт вторых сообщений: элементы
возвращаются с результатом duplicate и ссылкой на уже созданное сообщение.
Idempotency-Key на пакете при этом тоже работает — но client_ref надёжнее:
он переживает и частичный повтор, когда пакет пересобрали.
Ответ пакета, в котором есть элемент, отвергнутый по нашей причине
(internal_error, provider_unavailable), к ключу не приколачивается: повтор
с тем же ключом выполняется заново, принятые элементы возвращаются
duplicate, отвергнутые принимаются.
Повтор по client_ref не тратит окно анти-флуда: он не создаёт сообщения.
Защита по client_ref держится, пока хранится само сообщение, — три года
(см. Данные и сроки хранения). Повтор с тем же
client_ref спустя этот срок создаст новое сообщение. Для ретраев это не
ограничение, но переиспользовать один и тот же client_ref годами нельзя.