Термин idempotent берет свое начало в математике. В нем говорится, что «если приложение будет иметь тот же результат, если будет запущено один или несколько раз». Например, если вы умножите значение на 1 или 0 несколько раз, ответ будет получен через 1 или N раз, поэтому они считаются идемпотентными. Однако, если вы добавляете результат 1, 1 или N раз, он будет изменять значение каждый раз и, следовательно, не будет считаться идемпотентным.
Самый распространенный пример «реального мира», о котором вы прочитаете, — это вызов лифта, как описано в этой цитате из википедии.
Первоначальное нажатие кнопки переводит систему в состояние запроса, пока запрос не будет удовлетворен. Последующие активации кнопки между первоначальной активацией и удовлетворением запроса не имеют никакого эффекта, если только система не предназначена для настройки времени для удовлетворения запроса на основе количества активаций.
Идемпотент в компьютерных науках
Как именно это применяется в компьютерных науках? Функция считается идемпотентной, если она не приводит к изменению после одного или нескольких запусков. Возможность запускать функцию, зная, что никаких изменений не произойдет, если только они не потребуются, по сути делает их более безопасными.
Представьте, что вы запускаете скрипт с десятью действиями, и скрипт не работает по независящей от вас причине, например, недоступность ресурса или сбой соединения на пятом шаге. Если десять функций не являются идемпотентными, сценарий должен будет запускаться с того места, где он потерпел неудачу. Чтобы даже добиться этого, вам нужно будет либо изменить сценарий, либо встроить в сценарий другую логику для создания отправной точки, что может быть или не быть практичным, например, если на третьем этапе будет собрана информация, которая вам понадобится позже, вы бы все равно нужно выполнить этот шаг, несмотря ни на что. Это ложится бременем на пользователя сценария и не дает оптимального опыта работы с пользователем. Однако, если все функции были идемпотентными, вы можете просто перезапустить скрипт.
Примечание. Хотя, конечно, это не первая или единственная система, которая делает это, учитывая ее популярность, стоит отметить, что Ansible пытается применить эту технику ко всем созданным модулям.
Пример
Механизм создания идемпотентной функции состоит в том, чтобы сначала проверить состояние или значение, которое вы намереваетесь получить, и только если нет, то внесите изменения. Как вы можете видеть в этих надуманных примерах, первый пример не идемпотентен, а второй — нет.

>>> neighbors = ["nyc-rt01"]
>>>
>>> def update_list(neighbors, neighbor):
...     neighbors.append(neighbor)
...     return neighbors
...
>>> neighbors = update_list(neighbors, "nyc-rt02")
>>> neighbors = update_list(neighbors, "nyc-rt02")
>>> print(neighbors)
['nyc-rt01', 'nyc-rt02', 'nyc-rt02']
>>>

Примечание: результат включает nyc-rt02 несколько раз.

>>> neighbors = ["nyc-rt01"]
>>>
>>> def update_list_idempotently(neighbors, neighbor):
...     if neighbor not in neighbors:
...         neighbors.append(neighbor)
...     return neighbors
...
>>> neighbors = update_list_idempotently(neighbors, "nyc-rt02")
>>> neighbors = update_list_idempotently(neighbors, "nyc-rt02")
>>> print(neighbors)
['nyc-rt01', 'nyc-rt02']

Примечание. Результат включает в себя nyc-rt02 один раз, даже если попытаться «добавить nyc-rt02» несколько раз.

Бессилие в REST

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

Пример использования в реальной жизни

*_configМодули Ansible идемпотентны. Но что это значит, когда вы отправляете конфигурации через cli? В этом случае состояние, на которое ссылается модуль, заключается в том, существует ли уже конфигурация, а именно:как конфигурация отображается в «показательном прогоне». Повторюсь, это точное совпадение в прямом смысле слова, поэтому, хотя IOS примет «int gig0 / 1», который не будет соответствовать фрагменту конфигурации «interface GigabithEthernet0 / 1», который фактически отображается в конфигурации, то же самое верно. для несоответствия интервала. На самом деле нет никакой связи между тем, что примет cli, и тем, что отправит модуль. Таким образом, вы можете отправлять неверные команды, модуль просто вызовет ошибку, или у вас может быть несоответствие пробелов или синтаксиса, которые будут работать на cli, но не будут рассматриваться модулем как идемпотентная функция, поэтому модуль будет отправлять изменения конфигурации каждый раз.

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

  1. В первый раз применяется описание интерфейса config «int Gig1 / 0/24», и результат изменяется.
  2. Во второй раз модуль все еще пытается построить конфигурацию на «Gig1 / 0/24» и снова отправляет конфигурацию, так как не было точного совпадения.
  3. При третьем применении конфигурации к «интерфейсу GigabitEthernet1 / 0/24» обнаруживается совпадение в конфигурации, и никаких изменений не требуется, и, таким образом, модуль идемпотентен.

Заключение

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

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