Идемпотентность и повторы
Каждый вызов реального времени должен нести Idempotency-Key. Это не любезность ради лимитов — именно это делает повтор безопасным. Сеть отказывает после того, как поставщика уже спросили; без ключа единственный способ узнать, выполнилась ли проверка, — выполнить её снова и заплатить дважды.
Правило
Заголовок раздела «Правило»Передавайте значение, которое можете воспроизвести: UUID, ID заказа или хеш выполняемой работы. Сервер ограничивает его вашим аккаунтом, поэтому два пользователя не могут столкнуться.
| Тот же ключ | Полезная нагрузка | Результат |
|---|---|---|
| Новый ключ | любая | Выполняется как обычно, списывается |
| Тот же ключ | идентичная | Возвращается сохранённый ответ; replayed=true. Новое списание не производится. |
| Тот же ключ | другая | 409 idempotency_conflict — ключ привязан к полезной нагрузке, с которой он впервые пришёл |
| Тот же ключ | идентичная, первый вызов ещё выполняется | 409 request_in_progress с Retry-After |
Idempotency-Key ограничен 191 байтом, а записи повторов по умолчанию хранятся 30 дней.
replayed — это не cached
Заголовок раздела «replayed — это не cached»В ответе они выглядят похоже, но означают разное:
| Поле | Где | Что означает |
|---|---|---|
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 | Ничего не было отправлено. Повторите позже с тем же ключом. |
Единственное, чего никогда не стоит делать после таймаута, — отправлять новый ключ с той же работой: если первый вызов всё же прошёл, вы только что заплатили за проверку дважды.
Ошибки, возникающие здесь
Заголовок раздела «Ошибки, возникающие здесь»| HTTP | code |
|---|---|
| 400 | idempotency_key_required — заголовок отсутствует |
| 409 | request_in_progress — исходный вызов ещё выполняется |
| 409 | idempotency_conflict — ключ впервые использован с другой полезной нагрузкой |