Что такое idempotency в API и как избежать дубликатов запросов

6 минут чтения
Средний рейтинг статьи — 4.7

При разработке API часто возникает проблема повторных запросов. Клиент может отправить один и тот же запрос несколько раз из-за сетевых сбоев, таймаутов, повторных кликов пользователя или автоматических ретраев. Если сервер обрабатывает каждый такой запрос как новый, это может привести к дублирующим операциям: двойному списанию денег, созданию нескольких заказов или повторной отправке писем.

Именно для решения этой задачи используется idempotency.

Что такое idempotency

Идемпотентность — это свойство операции, при котором повторное выполнение запроса с теми же параметрами не меняет результат.

Проще говоря:

  • один запрос или десять одинаковых запросов → результат один и тот же.

Важно: идемпотентность не означает, что запрос выполняется только один раз. Он может быть обработан повторно, но эффект от обработки не должен дублироваться.

Идемпотентность и HTTP-методы

В HTTP идемпотентность частично заложена в семантику методов:

МетодИдемпотентенКомментарий
GETдаНе меняет состояние сервера
PUTдаЗаменяет ресурс целиком
DELETEдаПовторное удаление не меняет результат
POSTнетОбычно создаёт новые сущности
PATCHнетЧастичное изменение может быть неидемпотентным

На практике именно POST-запросы чаще всего требуют дополнительной защиты от дубликатов.

Откуда берутся дубликаты запросов

Даже если клиент написан аккуратно, повторные запросы — это норма, а не ошибка:

  • таймаут между клиентом и сервером;
  • автоматические ретраи в HTTP-клиентах;
  • повторная отправка формы пользователем;
  • мобильные сети с нестабильным соединением;
  • повторная доставка сообщений из очередей.

Если API не учитывает эти сценарии, дубликаты становятся неизбежными.

Что такое idempotency key

Самый распространённый способ защиты — idempotency key.

Это уникальный идентификатор, который клиент генерирует для операции и передаёт вместе с запросом, чаще всего в заголовке:

Idempotency-Key: 8f4e7c2a-1b6f-4d3a-9b6e-9b2c2f0c7a91

Смысл простой:

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

Базовый алгоритм обработки idempotency key

Типичная реализация на сервере выглядит так:

  1. Получить Idempotency-Key из запроса.
  2. Проверить, существует ли он в хранилище.
  3. Если ключ найден:
    • вернуть сохранённый ответ (статус + тело).
  4. Если ключ не найден:
    • выполнить операцию;
    • сохранить результат, связанный с этим ключом;
    • вернуть ответ клиенту.

Важно, чтобы проверка и сохранение выполнялись атомарно, иначе два параллельных запроса могут пройти одновременно.

Где хранить idempotency keys

Выбор хранилища зависит от нагрузки и требований:

  • Redis — самый популярный вариант, быстрый и с поддержкой TTL.
  • Реляционная БД — удобно, если операция и ключ связаны с транзакцией.
  • Key-value хранилища — подходят для высоконагруженных систем.

Обычно ключи хранят ограниченное время (например, 24 часа), чтобы не засорять хранилище.

Идемпотентность и транзакции

Для критичных операций (платежи, создание заказов) идемпотентность часто комбинируют с транзакциями:

  • сначала резервируется ключ;
  • затем выполняется бизнес-логика;
  • результат фиксируется вместе с ключом.

Если процесс упал посередине, повторный запрос сможет корректно завершить операцию или вернуть уже зафиксированный результат.

Частые ошибки при реализации

Несколько типичных проблем:

  • ключ не уникален — например, генерируется на сервере, а не на клиенте;
  • ключ не связан с телом запроса — клиент может отправить разные данные с одним ключом;
  • нет TTL — таблица с ключами бесконечно растёт;
  • возвращается новый ответ вместо сохранённого;
  • нет защиты от параллельных запросов.

Хорошая практика — логировать конфликты idempotency, чтобы понимать, как часто клиенты повторяют запросы.

Когда idempotency обязательна

Идемпотентность стоит внедрять, если API:

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

Для read-операций она обычно не нужна, а для write-операций — почти всегда желательна.

Итоги

Idempotency — это не дополнительная опция, а базовый механизм надёжности API. Повторные запросы будут всегда, и задача сервера — корректно их обрабатывать.

Кратко:

  • идемпотентность защищает от дубликатов;
  • чаще всего реализуется через Idempotency-Key;
  • требует атомарности и хранения результатов;
  • критична для финансовых операций.

Хорошо реализованная идемпотентность делает API устойчивым к сетевым сбоям и непредсказуемому поведению клиентов — а это именно то, чего ждут от production-систем.

6 минут чтения
Средний рейтинг статьи — 4.7

Настроить мониторинг за 30 секунд

Надежные оповещения о даунтаймах. Без ложных срабатываний