Повторите запрос, не выполняя работу дважды

Заголовок Idempotency-Key — каким запросам он нужен, чем отвечают на повторный запрос и как выбрать ключ.

3 мин чтения

Запрос, который выполняет флоу или двигает кредиты, несёт ваш собственный ключ в заголовке Idempotency-Key. Ключ называет одну единицу работы. На запрос, повторённый с его ключом, отвечают, а не выполняют его заново, поэтому повтор после таймаута или потерянного соединения ничего не выполняет дважды и ничего не списывает дважды.

Где нужен ключ

Заголовок обязателен для запросов, которые что-то тратят или двигают:

  • запрос, который выполняет флоу, — POST /v1/operations/execute;

  • движение кредитов клиента — POST /v1/customers/{externalUserId}/topup, POST /v1/customers/{externalUserId}/charge и POST /v1/customers/{externalUserId}/adjust.

Страница каждого ресурса помечает эти операции. Остальные операции заголовок не читают.

  • Запрос без заголовка или с пустым заголовком отклоняется с 400 и кодом idempotency_key_required. Ничего не выполняется.

  • Ключ — не длиннее 190 символов. Более длинный отклоняется с 422 и кодом invalid_request — до того, как что-либо зарезервировано, списано или начислено.

Чем отвечают на повтор

Повтор — это тот же запрос с тем же ключом. Чем на него отвечают, зависит от того, что сделал первый запрос.

ЗапросПовтор с его ключом
Выполнение флоуВыполнение, которое открыл первый запрос, в том состоянии, в котором оно находится в этот момент, с replayed, равным true: 202, пока выполнение не закончено, и 200 с его результатом, когда закончено. Заново ничего не выполняется
Движение кредитовПервый ответ — в течение 24 часов. После этого — счёт в его нынешнем виде. Кредиты двигаются один раз

Ответ с ошибкой в одних случаях сохраняется, а в других — нет.

  • Выполнение флоу закрепляет за собой ключ, как только выполнение появилось. Ошибка, которая пришла до этого, — flow_not_found, тело, которое не прошло проверку, — оставляет ключ свободным. Ошибка, которая пришла после, например invalid_flow_input, закрывает выполнение, и повтор его читает: 200, статус failed и код.

  • Движение кредитов сохраняет только успешный ответ. Отклонённый запрос можно отправить ещё раз с тем же ключом.

Другой запрос с занятым ключом

Ключ, который уже называет единицу работы, отклоняет другую. Ответ — 409 с кодом idempotency_conflict, и ничего не выполняется.

409 Conflict
{
  "error": {
    "code": "idempotency_conflict",
    "message": "The Idempotency-Key was already used with a different request body",
    "request_id": "6b2e9c4a-1d7f-4e3b-8a5c-0f9d2e7b4c61"
  }
}

Что считается другим запросом, зависит от того, что называет ключ.

  • Для выполнения флоу тело сравнивается байт в байт. Другой вход, другой context, другой execution_mode — и даже те же поля в другом порядке — дают другой запрос.

  • Для движения кредитов любое другое тело — другой запрос, пока хранится первый ответ. После этого движение кредитов сравнивается по клиенту, типу кредитов, виду движения и сумме.

Как выбрать ключ

  • Составляйте ключ из единицы работы: заказ и его шаг (order-42:email) или идентификатор задачи вашей очереди. Тогда каждый повтор этой работы несёт тот же ключ, а следующая единица работы получает новый.

  • Ключ, созданный случайно для каждой попытки, защищает только эту попытку. Повтор, который ваше приложение отправляет с новым ключом, — это новая работа, и за неё платят ещё раз.

  • Ключ принадлежит проекту. Два проекта могут использовать один и тот же ключ, а внутри проекта у каждой единицы работы — свой ключ.

  • Чтобы выполнить работу снова после неудачного запроса — с другим входом или другой моделью, — отправьте исправленный запрос с новым ключом.

Что читать дальше

  • Ключи идемпотентности — ключи, которые отправляют SDK, и ключ из задачи очереди.

  • Операции — запрос, который выполняет флоу, и вызовы модели, которые он сделал.

  • Коды ошибок — что значат коды отклонённого ключа и что делать с каждым.

  • Клиенты и кредиты — ключи пополнений, списаний и корректировок.

  • Быстрый старт — первый запрос с собственным ключом.

  • Обзор — остальные соглашения запроса.

  • Выполнения — прочитайте выполнение, которому принадлежит ключ, и его трассировку.