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 подписчика

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

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

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

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

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

Расскажите что-нибудь про транзакции. Это миф или реальность?

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

o_0

Всмысле  блять миф?

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

Как отменить то, что уже произошло? Путешествия во времени? Альтернативные реальности?

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

Транзакцию можно отменить в её процессе, не после её коммита, то есть завершения.

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

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

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

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

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

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

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

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

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

Речь идёт про распределенные транзакции. А какие вопросы могут быть к транзакции в рамках одного приложения?

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

Да точно такие же, если 'транзакция' не из одной атомарной операции состоит.

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

Транзакция ВСЕГДА состоит не из одной операции, в этом её суть

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

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

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

Можно, гуглите распределенные тарнзакции

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

XXX


шо есть транзакцыи?


YYY


как бы тебе объяснить


YYY


вот ты бежышь срать в толчок


YYY


но по дороге не донёс


YYY


и обосрался


YYY


так вот с транзакциями можно сделать так, будто ваще и не бежал и не обосрался

Вы смотрите срез комментариев. Чтобы написать комментарий, перейдите к общему списку

Темы

Политика

Теги

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

Сообщества

18+

Теги

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

Сообщества

Игры

Теги

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

Сообщества

Юмор

Теги

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

Сообщества

Отношения

Теги

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

Сообщества

Здоровье

Теги

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

Сообщества

Путешествия

Теги

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

Сообщества

Спорт

Теги

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

Сообщества

Хобби

Теги

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

Сообщества

Сервис

Теги

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

Сообщества

Природа

Теги

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

Сообщества

Бизнес

Теги

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

Сообщества

Транспорт

Теги

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

Сообщества

Общение

Теги

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

Сообщества

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

Теги

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

Сообщества

Наука

Теги

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

Сообщества

IT

Теги

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

Сообщества

Животные

Теги

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

Сообщества

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

Теги

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

Сообщества

Экономика

Теги

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

Сообщества

Кулинария

Теги

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

Сообщества

История

Теги

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

Сообщества

Недвижимость и ремонт

Теги

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

Сообщества