Интеграции и APIГайд

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

Короткое практическое объяснение идемпотентности: как повторить операцию без двойного эффекта, дублей и потерянных статусов.

·3 минуты чтения·
идемпотентностьповторыинтеграцииAPIстатусынадежность

Простое определение

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

Если пользователь, система или внешний контур повторили запрос из-за таймаута, потери ответа или сетевой ошибки, результат должен оставаться управляемым: мы либо возвращаем уже созданный результат, либо показываем текущее состояние той же операции, либо явно отказываем повтор по правилу.

Почему повтор не равен новой операции

В интеграциях повтор возникает постоянно:

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

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

Что нужно для идемпотентности

Обычно нужна не одна настройка, а набор договоренностей:

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

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

Пример мышления

Плохая логика:

  • пришел запрос;
  • создаем новую операцию;
  • отправляем во внешний контур;
  • если пришел повтор, создаем еще одну.

Рабочая логика:

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

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

sequenceDiagram
  participant Client as Клиент
  participant API as API
  participant Store as Операция
  participant Effect as Эффект

  Client->>API: запрос + operation id
  API->>Store: найти operation id

  alt операция новая
    Store-->>API: не найдена
    API->>Store: создать processing
    API->>Effect: выполнить один раз
    Effect-->>API: результат
    API->>Store: сохранить финал
    API-->>Client: результат
  else операция уже есть
    Store-->>API: текущий статус
    alt статус финальный
      API-->>Client: тот же результат
    else еще в обработке
      API-->>Client: текущий статус
    end
  end

Где хранить состояние

Идемпотентность почти всегда требует состояния. Команда должна понимать:

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

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

Связь с ошибками и очередями

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

Очередь может доставить сообщение больше одного раза. Вебхук может повториться. HTTP-клиент может повторить запрос после сетевой ошибки. Пользователь может обновить страницу или нажать кнопку снова.

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

Приемочные критерии

Для важной операции проверьте:

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

Если эти проверки невозможно сформулировать, команда пока не понимает, где проходит граница операции.

Дальше

Продолжить по теме

Следующий шаг — открыть материал «Синхронный вызов или очередь: как выбрать способ интеграции» и расширить этот чеклист или подход соседним практическим контекстом.

Открыть материал