Идемпотентность



Идемпотентная операция — операция, которая при многократном вызове оставляет систему в одном и том же состоянии. Это значит, что:

🔸 Возвращаемый результат один и тот же

🔸 Сайд эффекты не накапливаются



Неважно сколько раз вызван метод — эффект будет одинаковый. Что может быть сайд-эффектом: запись в БД, обновление статистики, запись в файл, изменение общих переменных.



Примеры идемпотентных операций:



Удалить элемент с id=50

(10 вызовов → 1 удаление)

Удалить элемент максимального размера

(10 вызовов → 10 удалённых элементов)

Прочитать число из БД, умножить результат на 2 и вернуть пользователю

Прочитать число из БД и обновить статистику запросов



В чём смысл?



Идемпотентные операции повышают устойчивость системы.



Допустим, мы отправили запрос на сервер, и соединение пропало. Спустя 3 секунды восстановилось. Возникает дилемма:



🤔 Отправить запрос ещё раз? Но вдруг он уже был обработан…

🤔 Может не отправлять? А если предыдущий пропал…



Запрос либо дублируется, либо теряется. Для идемпотентного запроса такой проблемы нет, можно спокойно отправить его ещё раз.



На собеседованиях вопрос идемпотентности обычно обсуждают со стороны HTTP вызовов. Нужно сказать, что GET, PUT and DELETE идемпотентные, а POST — нет.



Но жизнь чуть сложнее.



🔹 Во-первых, идемпотентность зависит от бизнес-логики, а не от выбранного метода



Здесь самое сложное — держать под контролем сайд эффекты. Возьмём как пример увеличение счётчика в БД:



UPDATE t SET value=value+1



Как сделать его идемпотентным?



Добавить в таблицу (и сущность) поле version. Клиент передаёт номер текущей версии при обновлении. Запрос получается такой:



UPDATE t SET value=value+1, version=version+1 WHERE version=88



🔹 Во-вторых, POST запросы можно сделать идемпотентными. Например так:



Клиент генерирует ID и добавляет его в хэдер HTTP запроса:



Idempotency-Key: 4872934



Сервис хранит у себя список ID недавних запросов. Если операции с таким ID ещё не было, сервис начнет выполнение.



Процесс фильтрации дубликатов называется дедупликацией.



Выглядит как лишняя сложность, нужна ли вообще идемпотентность?



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