Идемпотентный метод
Метод HTTP является идемпотентным, если повторный идентичный запрос, сделанный один или несколько раз подряд, имеет один и тот же эффект, не изменяющий состояние сервера. Другими словами, идемпотентный метод не должен иметь никаких побочных эффектов (side-effects), кроме сбора статистики или подобных операций. Корректно реализованные методы GET , HEAD , PUT и DELETE идемпотентны, но не метод POST . Также все безопасные методы являются идемпотентными.
Для идемпотентности нужно рассматривать только изменение фактического внутреннего состояния сервера, а возвращаемые запросами коды статуса могут отличаться: первый вызов DELETE вернёт код 200 , в то время как последующие вызовы вернут код 404 . Из идемпотентности DELETE неявно следует, что разработчики не должны использовать метод DELETE при реализации RESTful API с функциональностью удалить последнюю запись.
Обратите внимание, что идемпотентность метода не гарантируется сервером, и некоторые приложения могут нарушать ограничение идемпотентности.
GET /pageX HTTP/1.1 идемпотентен. Вызвавший несколько раз подряд этот запрос, клиент получит тот же результат:
GET /pageX HTTP/1.1 GET /pageX HTTP/1.1 GET /pageX HTTP/1.1 GET /pageX HTTP/1.1
POST /add_row HTTP/1.1 не идемпотентен; если его вызвать несколько раз, то он добавит несколько строк:
POST /add_row HTTP/1.1 POST /add_row HTTP/1.1 -> Adds a 2nd row POST /add_row HTTP/1.1 -> Adds a 3rd row
DELETE /idX/delete HTTP/1.1 идемпотентен, даже если возвращаемый код отличается:
DELETE /idX/delete HTTP/1.1 -> Returns 200 if idX exists DELETE /idX/delete HTTP/1.1 -> Returns 404 as it just got deleted DELETE /idX/delete HTTP/1.1 -> Returns 404
Материалы для изучения
Общие
- Определение идемпотентности в спецификации HTTP.
Технические
- Описание общих идемпотентных методов: GET , HEAD , PUT , DELETE , OPTIONS
- Описание общих неидемпотентных методов: POST
Found a content problem with this page?
- Edit the page on GitHub.
- Report the content issue.
- View the source on GitHub.
This page was last modified on 12 нояб. 2023 г. by MDN contributors.
Your blueprint for a better internet.
MDN
Support
- Product help
- Report an issue
Our communities
Developers
- Web Technologies
- Learn Web Development
- MDN Plus
- Hacks Blog
- Website Privacy Notice
- Cookies
- Legal
- Community Participation Guidelines
Visit Mozilla Corporation’s not-for-profit parent, the Mozilla Foundation.
Portions of this content are ©1998– 2024 by individual mozilla.org contributors. Content available under a Creative Commons license.
Что такое идемпотентность http методов и почему она важна
Идемпотентность — это свойство операции, при котором её повторное применение к ресурсу не приводит к изменению его состояния. Другими словами, если вы выполняете идемпотентную операцию несколько раз, состояние ресурса будет таким же, как при однократном выполнении. В противном случае операция является не идемпотентной.
Идемпотентность HTTP запросов — это свойство определенных HTTP методов, при котором повторное выполнение одного и того же запроса с теми же параметрами не изменяет состояние ресурса на сервере. Другими словами, идемпотентные запросы можно выполнять несколько раз, а результат будет как при однократном запросе.
Идемпотентность обеспечивает надежность и предсказуемость взаимодействия между клиентами и серверами. Она гарантирует, что повторные запросы не вызовут неожиданных или нежелательных изменений на сервере. Это важно в критических системах, например банковские приложения, где дублирование операций может иметь серьезные последствия. В сетевых условиях могут возникать сбои, и запросы могут быть потеряны или задублированы. Также, в случае сбоя, запросы могут выполняться в непредсказуемом порядке. Идемпотентные операции позволяют клиентам безопасно повторять запросы, не беспокоясь о возможных проблемах в сети. В идемпотентных операциях сервер может использовать кэширование без опасения, что это повлияет на конечный результат. Это способствует улучшению производительности и отзывчивости системы. Идемпотентные операции позволяют серверам игнорировать повторяющиеся запросы, что может снизить нагрузку на серверы и сеть.
Эти факторы делают идемпотентность важным аспектом при проектировании сервисов, особенно в условиях распределенных сред. Идемпотентность помогает увеличить надежность, эффективность и предсказуемость работы систем. Следовательно обеспечивается лучший пользовательский опыт и более надежное функционирование приложений.
Идемпотентные HTTP запросы
В RESTful идемпотентными являются HTTP методы GET, PUT, DELETE, потому что повторный вызов любого из этих запросов с теми же данными и URI приведет к тому же состоянию ресурса, что и при первом запросе.
Пример запроса | Состояние ресурса до первого вызова запроса | Состояние ресурса после первого вызова запроса | Состояние ресурса после повторного вызова запроса |
---|---|---|---|
GET v1/users | |||
PUT v1/user/1 BODY: | |||
DELETE v1/user/1 | Ресурс пользователь с идентификатором – 1 не существует | Ресурс пользователь с идентификатором – 1 не существует |
Не идемпотентные HTTP запросы
К не идемпотентным запросам в RESTful относятся POST и PATCH, т.к. повторный вызов идентичных запросов может привести к изменению состояния ресурса. Применительно к POST запросу может быть создан дубль ресурса. Повторный вызов идентичного PATCH запроса может привести к изменению состояния ресурса.
Рассмотрим пример не идемпотентного PATCH запроса. Предположим, нам необходимо с помощью PATCH запроса реализовать увеличение возраста пользователя на указанную величину. Существует ресурс пользователь < “id”:”1”, “lastname”: “Иванов”, “firstname” : “Петр”, “age”:32 > . Получив от клиента запрос PATCH v1/user/1 с телом < “id”:”1”, “ageIncrement”: 3 > сервер изменит состояние ресурса на пользователь на < “id”:”1”, “lastname”: “Иванов”, “firstname” : “Петр”, “age”:35 >, т.е увеличит значение атрибута age на значение ageIncrement. Каждый последующий вызов идентичного запроса будет увеличивать значение age на значение ageIncrement, т.е после повторного вызова идентичного запроса состояние ресурса на пользователь будет < “id”:”1”, “lastname”: “Иванов”, “firstname” : “Петр”, “age”:38 >.
Повторный вызов POST и PATCH запросов может привести к изменению состояния ресурса. Но POST и PATCH можно сделать идемпотентными, достаточно передать вместе с запросом ключ идемпотентности.
Ключ идемпотентности (Idempotency-Key)
Idempotency-Key — это уникальный идентификатор, который помогает серверу отслеживать идемпотентность запросов. Клиенты включают Idempotency-Key в запросы, чтобы сервер мог определить, что запрос уже обработан. Если сервер обнаруживает Idempotency-Key вновь, он может игнорировать дублирующий запрос и вернуть тот же результат, что и в первый раз.
Пример использования ключа идемпотентности
Вы системный аналитик на проекте мобильное приложение для заказа доставки еды. Одной из функций является «Мультизаказ», т.е. можно сделать новый заказ, пока существующий еще не доставлен. В процессе эксплуатации приложения некоторые пользователи начали жаловаться, что им доставляют по 2 идентичных заказа. Разбор кейсов показал, что сервер при получении двух идентичных POST запросов просто создавал новый заказ.
Пример POST запроса на создание заказа
При повторном получении этого запроса сервер создаст еще один заказ. Но если мы будем передавать в запросе Idempotency-Key, то сервер получив запрос проверит значение Idempotency-Key. Если заказ с таким Idempotency-Key уже был создан ранее, то сервер просто вернет статус заказа.
Пример идемпотентного POST запроса на создание заказа
Идемпотентность — Idempotence
Свойство o действия кнопки включения / выключения на панели управления поездом знак назначения. Нажатие кнопки «Вкл.» (Зеленая) является идемпотентной операцией, поскольку она имеет одинаковый эффект как при однократном, так и при многократном нажатии. Аналогичным образом, нажатие Off является идемпотентным.
Idempotence (UK :,US : ) является свойством некоторых операций в математике и информатика, в результате чего их можно применять несколько раз без изменения результата за пределами первоначального приложения. Концепция идемпотентности возникает в ряде мест в абстрактной алгебре (в частности, в теории проекторов и операторов замыкания ) и в функциональном программировании. (в котором он связан со свойством ссылочной прозрачности ).
Термин был введен Бенджамином Пирсом в контексте элементов алгебр, которые остаются инвариантными при возведении в положительную целочисленную степень, и буквально означает «(качество обладания) той же степени «, от идема + власть (то же + сила).
- 1 Определение
- 2 Примеры
- 2.1 Идемпотентные функции
- 3.1 Примеры информатики
Определение
Элемент x магмы (M, •) называется идемпотентным, если:
Если все элементы идемпотентны относительно •, то • называется идемпотентным. Формула ∀x, x • x = x называется законом идемпотентности для •.
Примеры
- Натуральное число 1 является идемпотентным элементом по отношению к умножению (поскольку 1 × 1 = 1), и поэтому 0 (поскольку 0 × 0 = 0), но никакое другое натуральное число не равно (например, 2 × 2 = 2 не выполняется). По последней причине умножение натуральных чисел не является идемпотентной операцией. Более формально, в моноиде (ℕ, ×) идемпотентные элементы равны только 0 и 1.
- В магме (M, •) тождество элемент e или поглощающий элемент a, если он существует, является идемпотентным. В самом деле, e • e = e и a • a = a.
- В группе (G, •) единичный элемент e является единственным идемпотентным элементом. В самом деле, если x — такой элемент группы G, что x • x = x, то x • x = x • e и, наконец, x = e умножением слева на обратный элемент x.
- Взятие пересечения x∩ y двух множеств x и y является идемпотентной операцией, поскольку x∩x всегда равно x. Это означает, что выполняется закон идемпотентности ∀x, x∩x = x. Аналогично, объединение двух множеств — идемпотентная операция. Формально в моноидах ( (E), ∪) и ( (E), ∩) набора мощности набора E с набором объединение ∪ и установить пересечение ∩ соответственно, все элементы идемпотентны; следовательно, ∪ и ∩ — идемпотентные операции на (E).
- В моноидах (, ∨) и (,) булевой области с логической дизъюнкцией ∨ и логической конъюнкцией ∧ соответственно, все элементы идемпотентны.
- В логическом кольце умножение идемпотентно.
- В Тропическом полукольце сложение идемпотентно.
Идемпотентные функции
В моноиде (E, ∘) функций из множества E в себя с композицией функций ∘, идемпотентными элементами являются функции f: E → E такие, что f ∘ f = f, другими словами такие, что для всех x в E, f (f (x)) = f (x) (изображение каждого элемента в E является фиксированной точкой f). Например:
- Принятие абсолютного значения abs (x) из целого числа x является идемпотентной функцией по следующей причине: abs (abs (x)) = abs ( x) истинно для каждого целого числа x. Это означает, что выполняется abs ∘ abs = abs, то есть abs является идемпотентным элементом в наборе всех функций (от целых до целых) по отношению к композиции функций. Следовательно, abs удовлетворяет приведенному выше определению идемпотентной функции.
Другие примеры включают:
- функция идентичности идемпотентна;
- константа функции идемпотентны;
- функции пола, потолка и дробной части являются идемпотентными;
- подгруппа сгенерировала функцию из набора мощности группы к самой себе идемпотентна;
- функция выпуклой оболочки из набора степеней аффинного пространства над действительными к себе есть идемпотентный;
- закрывающие и внутренние функции набора мощности топологического пространства по отношению к самому себе идемпотентны;
- Звезда Клини и Клини плюс функции набора мощности моноида к самому себе являются идемпотентными;
- идемпотентными эндоморфизмамивекторное пространство являются его проекциями.
Если множество E имеет n элементов, мы можем разделить его на k выбранных фиксированных точек и n — k нефиксированных точек под f, и тогда k будет количество различных идемпотентных функций. Следовательно, принимая во внимание все возможные разбиения,
— общее количество возможных идемпотентных функций на множестве. Целочисленная последовательность количества идемпотентных функций, заданная суммой выше для n = 0, 1, 2, 3, 4, 5, 6, 7, 8,… начинается с 1, 1, 3, 10, 41, 196, 1057, 6322, 41393,… (последовательность A000248 в OEIS ).
Ни свойство быть идемпотентным, ни свойство не быть не сохраняется при композиции функций. Как пример для первого, f (x) = x mod 3 и g (x) = max (x, 5) оба являются идемпотентными, но f ∘ g нет, хотя g ∘ f случается с быть. В качестве примера последнего, функция отрицания ¬ в булевой области не идемпотентна, а ¬ ∘ ¬ такова. Точно так же унарное отрицание — () действительных чисел не идемпотентно, а — () ∘ — ().
Информатика означает
В информатике термин идемпотентность может иметь другое значение в зависимости от контекста, в котором он применяется:
- в императивного программирования, подпрограмма с побочными эффектами идемпотентна, если состояние системы остается неизменным после одного или нескольких вызовов, другими словами, если функция из пространства состояний системы в сама связанная с подпрограммой является идемпотентной в математическом смысле, данном в определении ;
- в функциональном программировании, чистая функция является идемпотентной, если она идемпотентна в математическом смысле задано в определении.
Это очень полезное свойство во многих ситуациях, поскольку оно означает, что операцию можно повторять или повторять столько раз, сколько необходимо, без возникновения непредвиденных эффектов. При неидемпотентных операциях алгоритму, возможно, придется отслеживать, была ли операция уже выполнена или нет.
Примеры информатики
Функция поиска имени и адреса клиента в базе данных обычно идемпотентна, так как это не приведет к изменению базы данных. Точно так же изменение адреса клиента на XYZ обычно идемпотентно, потому что окончательный адрес будет одним и тем же независимо от того, сколько раз отправляется XYZ. Однако размещение заказа на тележку для клиента обычно не идемпотентно, так как выполнение вызова несколько раз приведет к размещению нескольких заказов. Отмена заказа идемпотентна, потому что заказ остается отмененным независимо от количества сделанных запросов.
Однако композиция идемпотентных методов или подпрограмм не обязательно является идемпотентной, если более поздний метод в последовательности изменяет значение, от которого зависит предыдущий метод — идемпотентность не закрывается при композиции. Например, предположим, что начальное значение переменной равно 3, и существует последовательность, которая считывает переменную, затем изменяет ее на 5, а затем читает ее снова. Каждый шаг в последовательности идемпотентен: оба шага, считывающие переменную, не имеют побочных эффектов, и изменение переменной на 5 всегда будет иметь тот же эффект, независимо от того, сколько раз она выполняется. Тем не менее, однократное выполнение всей последовательности дает результат (3, 5), а выполнение второй раз дает результат (5, 5), поэтому последовательность не идемпотентна.
В протоколе передачи гипертекста (HTTP) идемпотентность и безопасность являются основными атрибутами, разделяющими HTTP-глаголы. Из основных HTTP-глаголов GET, PUT и DELETE должны быть реализованы идемпотентным образом в соответствии со стандартом, но POST не обязательно. GET извлекает ресурс; PUT хранит контент на ресурсе; и DELETE удаляет ресурс. Как и в приведенном выше примере, чтение данных обычно не имеет побочных эффектов, поэтому оно идемпотентное (фактически нульпотентное ). Хранение и удаление заданного набора контента обычно являются идемпотентными, если в запросе указывается местоположение или идентификатор, который однозначно идентифицирует этот ресурс и только этот ресурс в будущем. Операции PUT и DELETE с уникальными идентификаторами сводятся к простому случаю присвоения неизменяемой переменной значения или нулевого значения, соответственно, и являются идемпотентными по той же причине; конечный результат всегда совпадает с результатом первоначального выполнения, даже если ответ отличается.
Нарушение требования уникальной идентификации при хранении или удалении обычно вызывает нарушение идемпотентности. Например, сохранение или удаление заданного набора контента без указания уникального идентификатора: запросы POST, которые не обязательно должны быть идемпотентными, часто не содержат уникальных идентификаторов, поэтому создание идентификатора делегируется принимающей системе, которая затем создает соответствующий новый рекорд. Точно так же запросы PUT и DELETE с неспецифическими критериями могут приводить к различным результатам в зависимости от состояния системы — например, к запросу на удаление самой последней записи. В каждом случае последующие исполнения будут дополнительно изменять состояние системы, поэтому они не будут идемпотентными.
В обработке потока событий идемпотентность относится к способности системы производить одинаковый результат, даже если один и тот же файл, событие или сообщение получено более одного раза.
В архитектуре загрузка-сохранение инструкции, которые могут вызвать отказ страницы, являются идемпотентными. Таким образом, если происходит сбой страницы, ОС может загрузить страницу с диска, а затем просто повторно выполнить команду с ошибкой. В процессоре, где такие инструкции не идемпотентны, работа с ошибками страниц намного сложнее.
При переформатировании вывода ожидается, что pretty-printing будет идемпотентным. Другими словами, если результат уже «красивый», то для красивого принтера делать нечего.
В сервис-ориентированной архитектуре (SOA) многоступенчатая Процесс оркестровки, полностью состоящий из идемпотентных шагов, может быть воспроизведен без побочных эффектов, если какая-либо часть этого процесса не удалась.
Многие идемпотентные операции часто имеют способы «возобновить» процесс, если он был прерван, — способы, которые заканчиваются намного быстрее, чем начинание с самого начала. Например, возобновление передачи файлов, синхронизация файлов, создание сборки программного обеспечения, установка приложения и всех его зависимостей с помощью диспетчера пакетов и т. Д.
Примеры применения
Типичная кнопка перехода — пример идемпотентной системы
Примеры применения, с которыми многие люди могут столкнуться в своей повседневной жизни, включают лифт кнопки вызова и кнопки перехода. Первоначальное нажатие кнопки переводит систему в состояние запроса, пока запрос не будет удовлетворен. Последующие активации кнопки между первоначальной активацией и удовлетворением запроса не имеют никакого эффекта, если только система не предназначена для настройки времени для удовлетворения запроса на основе количества активаций.
См. Также
- Двухуровневый набор
- Оператор замыкания
- Фиксированная точка (математика)
- Идемпотент кода
- Идемпотентный анализ
- Идемпотентная матрица
- Идемпотентное отношение — обобщение идемпотентности на бинарные отношения
- Инволюция (математика)
- Итерированная функция
- Список матриц
- Нильпотентная
- Чистая функция
- Ссылочная прозрачность
Ссылки
Дополнительная литература
Найдите idempotence в Wiktionary, бесплатном словаре. В Викиучебнике есть дополнительная информация по теме: Idempotence Викиверситет имеет обучающие ресурсы о Portal: Computer Science - “idempotent ”на FOLDOC
- Goodearl, KR (1991), регулярные кольца фон Неймана (2-е изд.), Малабар, Флорида. : Robert E. Krieger Publishing Co. Inc., стр. Xviii + 412, ISBN 978-0-89464-632-4 , MR1150975
- Gunawardena, Jeremy (1998), «Введение в идемпотентность» (PDF), в Gunawardena, Джереми (ред.), Idempotency. По материалам семинара, Бристоль, Великобритания, 3–7 октября 1994 г., Кембридж: Cambridge University Press, стр. 1–49, Zbl0898.16032
- , Энциклопедия Mathematics, EMS Press, 2001 [1994]
- Hazewinkel, Michiel ; Губарени, Надия; Кириченко В. В. (2004), Алгебры, кольца и модули. т. 1, Mathematics and its Applications, 575, Dordrecht: Kluwer Academic Publishers, стр. Xii + 380, ISBN 978-1-4020-2690-4 , MR2106764
- Лам, Т.Ю. (2001), Первый курс некоммутативных колец, Тексты для выпускников по математике, 131 (2-е изд.), Нью-Йорк: Springer-Verlag, стр. Xx + 385, DOI : 10.1007 / 978-1-4419-8616-0, ISBN 978-0-387-95183-6 , MR1838439
- Лэнг, Серж (1993), Алгебра (третье изд.), Чтение, Массачусетс: Addison-Wesley, ISBN 978-0-201-55540-0 , Zbl0848.13001 стр. 443
- Пирс, Бенджамин. Линейная ассоциативная алгебра 1870.
- Польчино Милиес, Сезар; Сегал, Сударшан К. (2002), Введение в групповые кольца, алгебры и приложения, 1, Dordrecht: Kluwer Academic Publishers, стр. Xii + 371, doi : 10.1007 / 978-94-010-0405-3, ISBN 978-1-4020-0238-0, MR1896125
Почему важна идемпотентность и как писать идемпотентные bash-скрипты
Идемпотентность помогает проектировать более надёжные системы. Это математическая концепция, которую должен понимать каждый разработчик. Операция считается идемпотентной, если её многократное выполнение приводит к тому же результату, что и однократное выполнение. Например, умножение на 1 — идемпотентная операция.
- Идемпотентность HTTP-методов
- Очереди сообщений
- Убедитесь в идемпотентности задач, которые выполняете через воркер
- SQL-миграции
- Денормализованные данные
- Как писать идемпотентные bash-скрипты
- Bash-идиомы
- Создание пустого файла
- Создание директории
- Создание символической ссылки
- Удаление файла
- Изменение файла
- Проверка существования переменной, файла или директории
- Форматирование устройства
- Монтирование устройства
Умножение на ноль — тоже идемпотентная операция.
Ключевая концепция, которую нужно запомнить: однократное выполнение операции может иметь побочные эффекты, но повторное выполнение этой же операции не приведёт ни к чему другому, кроме того, что было сделано при первом выполнении. То есть присваивание — идемпотентная операция.
Вы можете присваивать x значение 4 сколько угодно раз, но x всё равно будет иметь значение 4. При этом присваивание x значения 4 один раз отличается от нуля.
Бесплатные курсы по программированию в Хекслете
- Освойте азы современных языков программирования
- Изучите работу с Git и командной строкой
- Выберите себе профессию или улучшите навыки
Идемпотентность HTTP-методов
HTTP-методы могут быть идемпотентными или нет.
DELETE — идемпотентный метод. Вы можете сколько угодно раз использовать DELETE, но результат будет всегда таким же, как после первого выполнения операции. Например, DELETE /users/4/contacts/3 удаляет контакт с ID 3. Если вы выполните эту же операцию ещё раз, ничего не произойдёт, так как контакт уже удалён.
GET — тоже идемпотентный метод. Это даже не просто идемпотентный, но ещё и безопасный метод. А безопасные методы можно сравнить с умножением на единицу. Умножать на 1 можно сколько угодно раз, результат всегда будет одинаковым. GET просто получает ресурс. Например, никогда не стоит использовать нормальные ссылки для удаления ресурсов.
POST не относится к идемпотентным методам. При каждом выполнении POST можно ждать побочных эффектов. Например, когда вы используете POST для отправки данных из контактной формы, отправляется письмо.
Потребители и провайдеры используют эту концепцию, когда речь идёт об API. Дизайн с учётом этой концепции позволяет соблюдать правило наименьшего удивления.
NB! Правило наименьшего удивления или principle of least astonishment гласит, что результат выполнения операции должен быть очевидным и предсказуемым по названию операции. Полезно ознакомиться со статьями «Именование в программировании» и «Ошибки именования в программировании».
Очереди сообщений
Представьте, что разрабатываете веб-приложение для управления мероприятиями. В нём есть функция добавления пользователей в список приглашённых на то или иное мероприятие. То есть на одно мероприятие можно пригласить сколько угодно людей. Для ускорения процесса вы решаете отправлять приглашения через воркер. Когда пользователь оформляет мероприятие, сообщения отправляются в очередь. Воркер получает эти сообщения и отправляет приглашения на мероприятия.
Это очень распространённый паттерн, и, если вы его ещё не используете, стоит подумать о том, чтобы начать.
В какой-то момент вы замечаете проблемы с SMTP и понимаете, что ваши письма в какой-то момент перестали отправляться. Логи не позволяют определить этот момент или понять, какие письма не отправлены. Вы решаете вызвать функцию, которая снова отправит письма. Но понимаете, что не знаете, для каких мероприятий нужно вызывать эту функцию.
Здесь в игру вступает идемпотентность.
Убедитесь в идемпотентности задач, которые выполняете через воркер
Вернёмся к примеру с электронными письмами. Вы можете сохранять в базе данных дату отправки письма приглашённому человеку в соответствующем ряду таблицы. Если письмо уже отправлялось, то есть значение в базе данных отличается от NULL, повторно отправлять письмо не нужно. Очень простое решение. Также можно проверять, завершено ли оформление мероприятия. Если оформление не завершено, письмо отправлять не нужно.
- Убедитесь, что задача готова к исполнению. Если задача не готова к исполнению, ничего делать не надо.
- Убедитесь, что задача ещё не исполнена. Если она исполнена, ничего не нужно делать.
- Выполните задачу, занесите дату выполнения или другую информацию в базу данных. Запишите в лог, что задача выполнена. Например, укажите, что приглашение на такое-то мероприятие отправлено такому-то пользователю.
- Убедитесь, что задачи гранулированные. Нужно отправить пять писем? Запланируйте задачу, которая выполнит пять других задач. Пример кода ниже.
send_event_emails(event_id) send_event_email_to_invitee(event_id, invitee_id)
Увидели, что что-то идёт не так? Можно снова вызвать функцию, которая отправит все приглашения на все мероприятия. Снова проблемы, когда половина писем отправлена? Исправьте проблему и вызовите функцию снова. Достаточно просто выяснить, какие письма не были отправлены. В качестве бонуса: вы можете понять, сколько писем в день рассылается, когда шлётся больше всего писем и так далее.
Помните, некоторые очереди не гарантируют отправку одного письма один раз. К ним относится Amazon SQS. Поэтому ваши воркеры должны выполнять только идемпотентные задачи.
SQL-миграции
Когда вы выполняете SQL-миграции, позаботьтесь об их идемпотентности.
Например, вам нужно разделить таблицу пользователя на две. Одна таблица будет для пользователей (users), а вторая для деталей, которые не всегда важны (profiles). Вы помещаете внешний ключ user_id в в таблицу profiles. Получаете миграцию, которая берёт каждый ряд в users (SELECT * FROM users) и вставляет ряд с пользовательскими данными в profiles. Запускаете миграцию, но она крашится через час. Это происходит из-за значений NULL, которые вы не учли. Вы исправляете ошибку, снова запускаете миграцию, но вдруг понимаете, что для некоторых пользователей созданы по два профиля.
Этого можно избежать с помощью идемпотентного решения. Вместо SELECT * FROM users можно выбрать пользователей, у которых ещё нет ряда в profiles. С таким решением миграцию можно запускать сколько угодно раз. В ходе каждого запуска будут обработаны данные тех пользователей, у которых ещё нет профиля. Огромное преимущество этого подхода — вам не нужно останавливать приложение при выполнении миграции. Как только вы готовы развернуть новую версию, в которой используется profiles, можно вызвать функцию, которая обеспечит миграцию новых пользователей. Это не самый лучший пример, так как пользователь во время миграции может изменить какие-то данные в таблице users. Учитывайте этот момент.
Денормализованные данные
У вас есть приложение, в котором у каждого пользователя есть много документов. Пользователи могут искать документы по тегам. Теги приходят из разных источников: названия документов, директорий, имена авторов, собственно теги и так далее. Вы решаете держать все теги для всех документов в таблице tags. Это выглядит так:
- ID (хэш)
- Tag (текст тега)
- document _id (внешний ключ к документу)
Когда вы добавляете автора в документ, в таблицу tags попадают данные. Когда вы удаляете автора, соответствующий тег удаляется из таблицы.
Однажды вы замечаете в логах, что время от времени случались ошибки из-за проблемы кодировки символов. Вы фиксите проблему и разворачиваете приложение с обновлённым кодом. Однако видите, что много тегов отсутствует, и их нужно восстанавливать вручную.
Вместо функции add_tag_for_new_author вам нужно изначально сделать функцию update_tags_for_document. Эта функция не просто добавляет тег автора. Она проверяет документ, перестраивает список тегов и убеждается, что в базу данных попала корректная информация. При таком подходе таблица tags обрабатывается корректным способом: с помощью кэша. Вы можете удалить все ряды из таблицы и запустить update_tags_for_document. Требуется 2 секунды, чтобы обновить теги? Пусть этим занимается воркер, добавьте сообщение в очередь.
Как писать идемпотентные bash-скрипты
Иногда случается такое: вы пишете bash-скрипт, запускаете его, но через какое-то время он завершается из-за ошибки. Вы фиксите ошибку в системе и снова запускаете скрипт. Но часть шагов вашего скрипта падает с ошибкой, так как эти шаги уже были выполнены при первом запуске. Чтобы создавать отказоустойчивые системы, нужно писать идемпотентные программы.
Bash-идиомы
Ниже вы найдёте несколько советов и bash-идиом, которые помогут писать идемпотентные скрипты. Вы наверняка используете некоторые из них, не задумываясь о побочных эффектах.
Создание пустого файла
Это простая задача. Команда touch по умолчанию идемпотентная. Вы можете вызывать её много раз без проблем. Повторный вызов не повлияет на контент файла. Но он изменит время модификации файла. Если вы его используете, будьте осторожны.
touch example.txt
Создание директории
Никогда не используйте команду mkdir как есть. Применяйте её с флагом -p. Этот флаг гарантирует отсутствие ошибки при запуске mkdir, если директория уже существует.
mkdir -p mydir
Создание символической ссылки
Для создания символических ссылок используется такая команда:
ln -s source target
Но эта команда генерирует ошибку, если вы повторно вызовите её с существующей целью. Чтобы сделать команду идемпотентной, добавьте флаг -f.
ln -sf source target
Флаг -f удаляет целевой путь перед созданием символической ссылки, поэтому команда всегда будет успешной. Если вы ссылаетесь на директорию, нужно добавить флаг -n. В противном случае повторный вызов создаст символическую ссылку внутри директории.
mkdir a ln -sf a b ln -sf a b ls a a
Для безопасности всегда используйте такую команду:
ln -sfn source target
Удаление файла
Следующую ниже команду нежелательно использовать для удаления файлов:
rm example.txt
Чтобы команда игнорировала несуществующие файлы, надо использовать флаг -f.
rm -f example.txt
Изменение файла
Иногда необходимо добавить новую строку в файл, например, /etc/fstab. Нужно убедиться, что повторный запуск скрипта не приводит к добавлению строки ещё раз. Представьте, что используете такой скрипт:
echo "/dev/sda1 /mnt/dev ext4 defaults 0 0" | sudo tee -a /etc/fstab
Если вы запустите скрипт повторно, получите дублирующуюся запись в /etc/fstab. Один из способов сделать скрипт идемпотентным — проверить существование конкретных плейсхолдеров с помощью grep.
if ! grep -qF "/mnt/dev" /etc/fstab; then echo "/dev/sda1 /mnt/dev ext4 defaults 0 0" | sudo tee -a /etc/fstab fi
В данном случае -q обозначает тихий режим, а -F — режим фиксированной строки. Grep в фоновом режиме завершится с ошибкой, если /mnt/dev не существует, поэтому echo не вызовется.
Проверка существования переменной, файла или директории
Вы часто записываете в директорию, читаете из файла или выполняете простые строковые манипуляции с переменной. Например, у вас может быть инструмент, который создаёт новый файл, основываясь на определённых входящих данных.
echo "complex set of rules" > /etc/conf/foo.txt
Вычисление текста может быть дорогой операцией, поэтому вы не захотите писать его каждый раз, когда вызываете скрипт. Для идемпотентности вы проверяете существование файла с помощью флага -f встроенного свойства test командной оболочки.
if [ ! -f "/etc/conf/foo.txt" ]; then echo "complex set of rules" > /etc/conf/foo.txt fi
В данном случае -f — только пример. Есть много других флагов, в том числе:
- -d: директория;
- -z: строка с нулевой длиной;
- -p: пайп;
- -x: файл с разрешением на исполнение.
Например, если вы хотите установить бинарный файл, но только если его ещё не существует, можно использовать флаг -x таким способом:
# install 1password CLI if ! [ -x "$(command -v op)" ]; then export OP_VERSION="v0.5.6-003" curl -sS -o 1password.zip https://cache.agilebits.com/dist/1P/op/pkg/$OP_VERSION>/op_linux_amd64_$OP_VERSION>.zip unzip 1password.zip op -d /usr/local/bin rm -f 1password.zip fi
Это устанавливает файл op в /usr/local/bin. Повторный запуск скрипта не приведёт к повторной установке бинарного файла. В данном случае есть ещё одно преимущество. Вы можете легко обновить бинарный файл. Для этого достаточно удалить его из системы, обновить OP_VERSION env и повторно запустить скрипт. Список флагов и операторов можно получить с помощью man test.
Форматирование устройства
Для форматирования можно использовать такую команду:
mkfs.ext4 "$VOLUME_NAME"
Эта команда печатает атрибуты для заданного блока устройства. Соответственно, предварительное добавление значит продолжение форматирования только при ошибке blkid, которая сообщает, что соответствующий том ещё не отформатирован.
Монтирование устройства
Попытка монтировать том в существующий каталог может выполняться с помощью такой команды:
mount -o discard,defaults,noatime "$VOLUME_NAME" "$DATA_DIR"
Но если он уже установлен, возникнет ошибка. Можно проверять вывод команды mount. Но есть лучший вариант. Это использование команды mountpoint.
if ! mountpoint -q "$DATA_DIR"; then mount -o discard,defaults,noatime "$VOLUME_NAME" "$DATA_DIR" fi
Эта команда проверяет, является ли файл или каталог точкой монтирования. Флаг -q гарантирует, что она ничего не выводит и завершается в фоновом режиме. Если точка монтирования не существует, команда монтирует устройство.
Завершение
Вы узнали о важности идемпотентности, а также познакомились со способами написания идемпотентных скриптов. Многие из предложенных советов и трюков давно известны, но разработчики часто пренебрегают этими возможностями. Некоторые из представленных идиом очень специфичные. К таким относятся монтирование и форматирование. Тем не менее создание идемпотентных программ — выигрышная стратегия в долгосрочной перспективе. Поэтому полезно знать даже специфичные идиомы.
Адаптированный перевод статей The Importance of Idempotence by Antoine Leclair и How to write idempotent Bash scripts by Fatih Arslan.
Бесплатные курсы по программированию в Хекслете
- Освойте азы современных языков программирования
- Изучите работу с Git и командной строкой
- Выберите себе профессию или улучшите навыки