Питання 5 · Розділ 6

Що таке ідемпотентність (idempotency)?

Простіше: перший виклик робить роботу, всі наступні — нічого нового не відбувається.

Мовні версії: English Russian Ukrainian

Junior Level

Ідемпотентність — це властивість операції, при якій повторний виклик з тими самими параметрами не змінює результат після першого виконання.

Простіше: перший виклик робить роботу, всі наступні — нічого нового не відбувається.

Простими словами: скільки б разів ви не виконали операцію, результат буде таким самим, як після першого разу.

Приклади з життя:

  • Ідемпотентно: Вимкнути світло. Скільки разів не натисни кнопку “вимкнути” — світло все одно вимкнене.
  • Не ідемпотентно: Купити квиток. Кожна покупка — це новий квиток і списання грошей.

У контексті HTTP:

  • GET /users/1 — ідемпотентний. Скільки разів не запроси — дані не зміняться.
  • DELETE /users/1 — ідемпотентний. Перший раз видаляє, наступні підтверджують, що ресурсу немає.
  • POST /users — не ідемпотентний. Кожен виклик створює нового користувача.

Навіщо це потрібно?

Ідемпотентність дозволяє безпечно повторювати запити при мережевих помилках, не боячись створити дублікати.


Middle Level

Математичне визначення

$f(x) = f(f(x))$ — результат багаторазового застосування функції дорівнює результату одноразового.

// У HTTP ідемпотентність стосується стану сервера, а не коду відповіді. // Математична формула тут — аналогія, а не строге визначення.

Ідемпотентні HTTP методи:

  • GET, HEAD, OPTIONS — безпечні та ідемпотентні (не змінюють стан)
  • PUT — ідемпотентний (повна заміна: status = 'ACTIVE' десять разів = 'ACTIVE')
  • DELETE — ідемпотентний (перший виклик видаляє, інші підтверджують відсутність)

Неідемпотентні методи:

  • POST — зазвичай створює нові ресурси. 5 запитів POST /orders = 5 замовлень
  • PATCH — залежить від реалізації. {"age": 30} — ідемпотентний, {"op": "add", "path": "/tags"} — ні

Ідемпотентність vs Код відповіді

DELETE повернув 200, другий виклик — 404. Це все одно ідемпотентно! Ідемпотентність гарантує ідентичність стану системи, а не коду відповіді.

Safe vs Idempotent

Безпечний метод (GET) не змінює стан. Ідемпотентний метод (PUT, DELETE) може змінювати стан, але тільки один раз. Усі безпечні методи ідемпотентні, але не навпаки.

Патерн PRG (Post/Redirect/Get)

Рішення проблеми неідемпотентності POST у веб-інтерфейсах:

  1. Користувач натискає “Оплатити” (POST)
  2. Сервер обробляє і надсилає 303 See Other
  3. Браузер робить GET на сторінку успіху
  4. При F5 повторюється безпечний GET, а не небезпечний POST

Коли НЕідемпотентність бажана

Аудит-логи, event sourcing, фінансові транзакції — кожна спроба має бути записана, навіть якщо результат той самий.


Senior Level

Реалізація Idempotency Key для POST

У Highload-системах (платежі, замовлення) застосовується патерн Idempotency Key:

Алгоритм роботи сервера:

  1. Прийом: Отримуємо заголовок Idempotency-Key: <UUID>
  2. Перевірка: Шукаємо ключ у Redis з TTL (наприклад, 24 години)
  3. Стани:
    • Ключа немає: Створюємо запис зі статусом PROCESSING. Виконуємо логіку. Оновлюємо на COMPLETED, зберігаємо відповідь.
    • Статус PROCESSING: Повертаємо 409 Conflict (запобігає Race Condition)
    • Статус COMPLETED: Повертаємо збережену відповідь із Redis. Бізнес-логіка не запускається повторно.

Distributed Computing

Мережа ненадійна (Fallacies of Distributed Computing). Запит може:

  1. Не дійти до сервера
  2. Обробитись, але відповідь втратитись
  3. Зависнути (Timeout)

Ідемпотентність дозволяє клієнту безпечно повторювати (Retry) запит.

Продуктивність і Highload

  • Distributed Locks: Redlock додає затримку (latency)
  • Storage Cleanup: Зберігання відповідей за 24 години може займати багато місця в Redis
  • DB Level: INSERT ... ON CONFLICT DO NOTHING (PostgreSQL) — надійний “останній рубіж”

Edge Cases

  • Якщо Idempotency-Key той самий, але тіло інше — повернути 400 Bad Request
  • Ідемпотентність стосується основного ресурсу. Побічні ефекти (логування, статистика) допустимі
  • При тестуванні API завжди робіть два однакових виклики поспіль для перевірки

🎯 Шпаргалка для співбесіди

Обов’язково знати:

  • Ідемпотентність: повторний виклик з тими самими параметрами не змінює результат після першого виконання
  • Формула: f(x) = f(f(x)) — результат багаторазового застосування дорівнює одноразовому
  • Ідемпотентні методи: GET, HEAD, OPTIONS, PUT, DELETE
  • Неідемпотентні: POST (зазвичай), PATCH (залежить від реалізації)
  • Ідемпотентність стосується стану сервера, а не коду відповіді (DELETE 200 → 404 — все одно ідемпотентно)
  • Safe методи (GET, HEAD) не змінюють стан; усі Safe методи ідемпотентні, але не навпаки
  • Патерн PRG (Post/Redirect/Get) вирішує проблему повторної відправки POST-форми
  • Idempotency Key: UUID у заголовку + Redis-lock для безпечних повторів POST

Часті уточнюючі запитання:

  • Чому DELETE ідемпотентний, якщо другий раз повертає 404? — Ідемпотентність = стан сервера однаковий, а не код відповіді
  • Як зробити POST ідемпотентним? — Idempotency-Key у заголовку + зберігання результату в Redis
  • Що таке Retry Storm? — Коли тисячі клієнтів одночасно повторюють ідемпотентні запити
  • Навіщо потрібен Distributed Lock при Idempotency Key? — Щоб запобігти Race Condition при паралельних запитах

Червоні прапорці (НЕ говорити):

  • «Ідемпотентність означає однаковий код відповіді» — означає однаковий стан сервера
  • «POST не можна зробити ідемпотентним» — можна через Idempotency Key + distributed lock
  • «PATCH завжди не ідемпотентний» — залежить від операції (replace — ідемпотентний, add — ні)
  • «Ідемпотентність і Safe — одне й те саме» — Safe не змінює стан, ідемпотентний може змінювати, але один раз

Пов’язані теми:

  • [[Які HTTP методи ідемпотентні]]
  • [[Чому GET та DELETE ідемпотентні]]
  • [[Чи є POST ідемпотентним]]
  • [[Які основні HTTP методи використовуються в REST]]
  • [[В чому різниця між PUT та PATCH]]