Перейти к содержимому

Идемпотентность и повторы

Каждый вызов реального времени должен нести Idempotency-Key. Это не любезность ради лимитов — именно это делает повтор безопасным. Сеть отказывает после того, как поставщика уже спросили; без ключа единственный способ узнать, выполнилась ли проверка, — выполнить её снова и заплатить дважды.

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

Тот же ключПолезная нагрузкаРезультат
Новый ключлюбаяВыполняется как обычно, списывается
Тот же ключидентичнаяВозвращается сохранённый ответ; replayed=true. Новое списание не производится.
Тот же ключдругая409 idempotency_conflict — ключ привязан к полезной нагрузке, с которой он впервые пришёл
Тот же ключидентичная, первый вызов ещё выполняется409 request_in_progress с Retry-After

Idempotency-Key ограничен 191 байтом, а записи повторов по умолчанию хранятся 30 дней.

В ответе они выглядят похоже, но означают разное:

ПолеГдеЧто означает
replayedверхний уровеньЭтот вызов не дошёл до поставщика — вы повторили ключ.
cachedвнутри каждого результатаВердикт этого продукта был отдан из кэша результатов.

Повторный вызов воспроизводит исходный ответ, включая значение cached каждой записи. Ни один из флагов не меняет списанную сумму: повтор никогда не двигает деньги, а попадание в кэш всё равно тарифицируется по цене продукта за проверку.

Как факты хранятся только завершённые исходы. Результаты failed и unknown не кэшируются — более поздняя проверка того же идентификатора по тому же продукту снова спросит поставщика, а не воспроизведёт неубедительный ответ.

Что вы увиделиЧто делать
Таймаут или HTTP 500Отправьте заново исходное тело с исходным ключом. Исход неизвестен; именно для этого случая ключ и существует.
409 request_in_progressПодождите Retry-After, затем отправьте то же тело с тем же ключом.
409 idempotency_conflictКлюч уже несёт другую полезную нагрузку. Сгенерируйте новый ключ — не меняйте тело и не используйте старый ключ повторно.
429 realtime_rate_limitedПодождите Retry-After. Ничего не было отправлено, поэтому тот же ключ всё ещё не использован и его безопасно отправить.
503 realtime_route_unavailableНичего не было отправлено. Повторите позже с тем же ключом.

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

HTTPcode
400idempotency_key_required — заголовок отсутствует
409request_in_progress — исходный вызов ещё выполняется
409idempotency_conflict — ключ впервые использован с другой полезной нагрузкой