Складне словце, що мене спитали років п'ять тому на співбесіді.
На практиці це всього лише:
Це така властивість операції, що приводе систему в однаковий стан вне залежності від того була операція виконана один чи кілька разів.
Як і більшість визначень воно абсолютно точне і майже повністю непригодне до використання.
Давайте думати що нам може давати мислення про операції в системі як ідемпотентні і не ідемпотентні?
Одразу приходе в голову можливість ретраїв. Будь яку ідемпотентну операцію безпечно повторювати, якщо в нас немає впевненості в її успішному виконанні.
Більше того: операцію точно не можна безпечно повторювати, якщо вона не є ідемпотентною.
Так подумали і виробники купи мережевого заліза і софту.
В HTTP є методи: GET, POST, PUT, PATCH, DELETE
GET не має змінювати стан системи, а такі штуки ідемпотентні за замовчанням. Хоча ви легко можете це зломати, зав'язавши на це, наприклад, лічильник переглядів.
GET запити
можуть бути повторени браузером чи, навіть якоюсь з залізяк між вашим
комп'ютером і сервером: вишки зв'язку, супутники старлінк,
маршрутезатори провайдеру, чи маршрутезатори в датацентрі.
PUT і DELETE теж рахуються ідемпотентними, хоча це дуже легко зломати в реалізації.
Якщо ваш DELETE ендпойнд
видає помилки при неможливості знайти елемент для видалення він не буде
ідемпотентним: перший раз він видалить елемент і поверне успіх, а на
наступний впаде. Але щось в мережі може випадково повторити запит і ви
будете довго намагатись зрозуміти чому в вас в логах помилки. Не робіть
так.
Ключова відмінність PUT і PATCH як раз в ідемпотентності.
Тож PUT це щось типу
x = 10.
Таку зміну скільки не повторюй система все одно приходе до одного і того самого стану.А PATCH це вже щось типу
x++
, котрий повторювати може бути небезпечно.Дуже часто буває корисним зробити метод POST також ідемпотентним, вже не через мережеве залізо і софт. Нажаль це не завжди просто.
Якщо у вас є обмеження в системі на однакові об'єкти, то ви можете використовувати хеш від об'єкту (я
про хеші багато писав у попередніх постах) для перевірки присутності
об'єкту в таблиці чи колекції: якщо він там вже є, то повертати успіх
вне залежності від того коли і чого він там був створений. Такий підхід зробе POST ідемпотентним.
Але що робити, якщо в системі можуть бути однакові об'єкти?
Це ускладнює задачу, але не робить її неможливою.
В цілому все зводиться до того, щоб зробити з однакових об'єктів унікальні, а потім заборонити повтор унікальних об'єктів.
Як саме?
Додавши до об'єкта якусь унікальну випадкову послідовність, або дата до микросекунд.
Якщо не буде впевненості, що запит був оброблений успішно, то його можна буде повторити.
Якщо запит таки не був оброблений, то сервер його обробить.
Якщо вже був, то на сервері спрацює перевірка що такий об'єкт вже є і він просто нічого не стане робити.
Іноді це такою унікальною послідовністю можуть бути навіть ID, якщо є
можливість генерувати їх на клієнті: це буває коли викорстовуються GUID
чи щось подібне.
Але ідемпотентність не тільки про мережу і не надійне середовище. Іноді це просто спрощує код. В .NET правильною реалізацією Dispose вважається
ідемпотентна. Це дозволяє уникнути додаткових перевірок на володіння в
ієрархіях об'єктів і менше думати про порядок знищення об'єктів.
#WrittenInTheJungle #Misc