196

Идемпотентные операции в программировании

Всем привет, работаю java разработчиком 10 лет. В широком смысле вся разработка сводится к применению операций к данным. Операции могут обладать свойствами, в этом посте я бы хотел рассказать про свойство идемпотентности.

Пусть исходными данными будет число 5, а операцией будет "умножить на 2". В зависимости от количества n применений операции будем получать разный результат:

n = 0 -> 5
n = 1 -> 10
n = 2 -> 20 и так далее

Ничего удивительного. Но если возьмем операцию "умножить на 0" то результат будет следующий:

n = 0 -> 5
n = 1 -> 0
n = 2 -> 0 и так далее

Видно, что после n = 1 результат не меняется. Свойство операции давать одинаковый результат при однократном и многократном применении называется идемпотентностью. Получается, что операция "умножить на 0" идемпотентна, а "умножить на 2" нет.

Рассмотрим более близкую к бизнесу ситуацию. За баланс пользователя сотового оператора отвечает один сервис, а обработкой платежей занимается другой. Пользователь хочет пополнить телефон, деньги с карты уже списали, и осталось дождаться когда увеличится баланс. Нужно чтобы сервис баланса выполнил операцию "зачислить пользователю Васе 100р", а поручение на это дает сервис платежей:

Подача поручения и успешный ответ

Подача поручения и успешный ответ

Но что делать сервису платежей, если он не получил положительный ответ от сервиса баланса? Сетевое подключение не стабильно, и проблема может произойти:

  • в момент отправки поручения - тогда Вася не увидит свои 100р, будет писать в техподдержку

  • в момент доставки ответа - тогда пользователь увидит зачисление

Проблема в том, что сервис платежей не может достоверно понять, было обработано поручение или нет. Он видит только что не пришел положительный ответ. Сетевые проблемы исчезают так же быстро как появляются, и можно было бы попробовать отправить поручение еще раз (retry). Но что если в первый раз поручение таки было успешно обработано, и в случае ретрая баланс пользователя будет увеличен еще раз, в сумме на 200р?

Представим что операция увеличения баланса - идемпотентная. Тогда можно было бы ретраить подачу поручения множество раз (n >= 1), и в конечном счете получить успешный ответ. При этом повторные начисления будут исключены (так как результат операции для n > 1 такой же как для n = 1).

Чтобы операция пополнения баланса стала идемпотентной, нужно сначала предусмотреть возможность установить уникальность операции. Если Вася пополнял баланс на 100р дважды - вчера и сегодня - то такие операции должны интерпретироваться как разные. Получается, можно было бы различать операции по такому набору атрибутов: {имя пользователя, сумма, дата}. Еще лучше использовать синтетический идентификатор, например id операции списания с карты.

Итак, сервис платежей, помимо бизнес атрибутов, передает технический атрибут - id. Сервис баланса запоминает id обработанных ранее поручений, и игнорирует повторную обработку, в любом случае возвращая успешный ответ. Усилиями двух сервисов операция зачисления стала идемпотентной.

Если тема показалась интересной, и есть пожелания разобрать еще что-нибудь из бекенда, пишите их в комментарии. Всем удачных проектов!

Лига программистов

2.3K поста12K подписчика

Правила сообщества

- Будьте взаимовежливы, аргументируйте критику

- Приветствуются любые посты по тематике программирования

- Если ваш пост содержит ссылки на внешние ресурсы - он должен быть самодостаточным. Вариации на тему "далее читайте в моей телеге" будут удаляться из сообщества

1
Контент нейросетей
Автор поста оценил этот комментарий

Можно ли сделать транзакцией пример из поста, когда сервис платежей сообщает сервису баланса о платеже?

раскрыть ветку (1)
8
Автор поста оценил этот комментарий

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

Есть реализации распределенных транзакций, например протокол two-phase commit. На первом этапе отменить решение можно (rollback), на втором нельзя - в пример приводят католическую свадьбу, где священник получает согласие жениха и невесты, и после отозвать его невозможно. В случае с идемпотентными операциями переходим сразу ко второй фазе - когда отменить решение нельзя, можно только катиться вперед (в ретрае уведомлять сервис баланса).

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

показать ответы
9
Автор поста оценил этот комментарий

Какие-то уж совсем очевидные вещи. Номер пакета, id операции, транзакция этотбазовые основы

раскрыть ветку (1)
9
Автор поста оценил этот комментарий

Для реализации разных требований применяются разные подходы, не все совместимы между собой.

Когда дело касается передачи id, я бы рекомендовал задумываться каждый раз. Точно ли он нужен, или можно положиться на существующие атрибуты? Важна ли только уникальность, или также порядок? Будет ли id использован для партиционирования?

показать ответы
0
Автор поста оценил этот комментарий
Спасибо большое за лаконичный рассказ! Можете пожалуйста посоветовать книжки или статьи, где подробнее расписано про элементы безопасных операций такие как идемпотентность, транзакции и тд. Хотелось бы углубиться в эту сферу. Буду очень благодарен.
раскрыть ветку (1)
4
Автор поста оценил этот комментарий

Хороший обзор в разных областях даёт эта книга

Иллюстрация к комментарию
показать ответы
1
Автор поста оценил этот комментарий

А что это меняет? В унарном операторе "Умножить на 2" меняют аргумент и получают разные результаты (вот удивительно-то!)

раскрыть ветку (1)
2
Автор поста оценил этот комментарий

В случае из примера операция состоит из трёх команд: получить текущее значение переменной, использовать его как аргумент функции умножения, сохранить результат в эту же переменную.

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

Основное расхождение здесь в понимании, что считать результатом работы. Можно ли считать возвращаемое значение результатом работы, или обязательно должны быть эффекты вроде сохранения результата в память?

показать ответы
Контент нейросетей
Автор поста оценил этот комментарий

Вот из-за фундаментальной проблемы я и не уверен в существовании настоящих транзакций.

раскрыть ветку (1)
2
Автор поста оценил этот комментарий

Даже ввести единое понятие транзакции - нетривиальная задача )

0
DELETED
Автор поста оценил этот комментарий

Выглядит как очевидная штука, для которой зачем-то придумали умное слово

раскрыть ветку (1)
1
Автор поста оценил этот комментарий

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

0
Автор поста оценил этот комментарий

По первым строкам угадываю почерк Chatgpt)

раскрыть ветку (1)
0
Автор поста оценил этот комментарий

Это фантомное ощущение, я писал текст сам

Темы

Политика

Теги

Популярные авторы

Сообщества

18+

Теги

Популярные авторы

Сообщества

Игры

Теги

Популярные авторы

Сообщества

Юмор

Теги

Популярные авторы

Сообщества

Отношения

Теги

Популярные авторы

Сообщества

Здоровье

Теги

Популярные авторы

Сообщества

Путешествия

Теги

Популярные авторы

Сообщества

Спорт

Теги

Популярные авторы

Сообщества

Хобби

Теги

Популярные авторы

Сообщества

Сервис

Теги

Популярные авторы

Сообщества

Природа

Теги

Популярные авторы

Сообщества

Бизнес

Теги

Популярные авторы

Сообщества

Транспорт

Теги

Популярные авторы

Сообщества

Общение

Теги

Популярные авторы

Сообщества

Юриспруденция

Теги

Популярные авторы

Сообщества

Наука

Теги

Популярные авторы

Сообщества

IT

Теги

Популярные авторы

Сообщества

Животные

Теги

Популярные авторы

Сообщества

Кино и сериалы

Теги

Популярные авторы

Сообщества

Экономика

Теги

Популярные авторы

Сообщества

Кулинария

Теги

Популярные авторы

Сообщества

История

Теги

Популярные авторы

Сообщества