Search
Write a publication
Pull to refresh

Comments 13

Это хорошая статья на мой взгляд. Но у меня возникает вопрос. А что если исключение происходит в компенсирующем событии? Здесь нужно компенсирующее событие для компенсирующего события? Или как это работает?

Во первых, обработчики compensation logic должны быть покрыты тестами и точно отрабатывать.
Во вторых должно быть настроенно retry policy, дабы цепочка не нарушилась из-за кривого подключения к базе и т.п.
В третьих, недошедшие сообщения должны храниться в DLQ и в первую очередь обработаны.

Если есть вероятность что обработчики compensation logic будут переодически отрабатывать с исключениями, то можно сделать один ивент компенсации на всю транзакцию и настроить на него retry policy.

Спасибо за ответ. Идея понятна в принципе. Нр справедливости ради хотелось бы отметить, что retry policy можно настроить и на целевые события, и обойтись без компенсирующих.

Ибо если затык на уровне БД происходит, к примеру из-за таймаутов, допустим в том же методе бронирования, то отмена бронирования будет в 99% случаев обращаться, к примеру, к той же заблокированной таблице (по неизвестным нам причинам).

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

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

Во первых, ...
Во вторых, ...
...
В десятых, ...

Понимаете, в чем дело. Вы, как пример, приводите простой код, который корректен только для идеального случая, когда всё идёт как задумано, а когда, вот, начинаются вопросы, "а что, если вот это, или вот то пошло не так", то даёте только общие ответы, которые выглядят просто. Но, если все эти ответы: "во первых, во вторых", и т.п., начать воплощать в вашем простом коде, то в результате на один только код потребуется штуки три таких статьи, и любой, кто на этот код посмотрит, вполне резонно скажет: "- Да ну их на... эти ваши микросервисы".

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

И еще вы заблуждаетесь насчет "eventual consistency" и "saga". Потому что "saga" это как раз только "eventual" consistency и есть. Если вам нужна "полная" consistency, то вам нужна не saga, а "2PC" (two-phase commit) с распределенными блокировками, а это настолько сложно в реализации (опять-таки если делать всё правильно), что я даже никогда и не слышал, чтобы кто-то в реальности с этим связывался.

Меня давно интересовал случай, когда в саге упадёт откат одной из транзакций - тогда и "eventual consistency" не удастся достигнуть. Поэтому при работе например с деньгами никак нельзя уйти от two-phase commit или работать только с одной бд (но такое часто бывает невозможно).

Можно (и, как правило, нужно) в дополнение к "saga" и "compensating" использовать еще "transactional outbox". Но, опять-таки, это тоже дополнительное усложнение - вам уже придется не просто брать и отправлять сообщение второму сервису, а встраивать в первый еще какой-то планировщик, который будет по таймеру проверять этот "outbox" на наличие записей и отправлять во второй сервис сообщение до тех пор пока тот явно ответным сообщением не подтвердит, что он его обработал. А тут уже возникают еще новые вопросы, например, как подбирать интервал этого таймера чтобы и задержка в синхронизации данных сервисов была приемлемой, но при этом не перегружать брокер потоком одинаковых сообщений, или, например, следует ли установить какой-то лимит на количество повторных попыток, или нет. И т.д. и т.п.

Как вариант (что, по личному опыту, на самом деле, обычно и делают :) это вообще по сути забить на всё это, списав на то, что подобные ситуации (какой-то сервис, или брокер, или какая-нибудь из БД, или всё вместе, просто взяло и тупо внезапно упало в самый неподходящий момент) они всё-таки нетипичны и, в случае чего, админы вместе с поддержкой руками будут разруливать проблемы типа "продали клиенту несуществующий товар" или "деньги за заказ взяли, а заказ на сборку так и не поступил" и прочие, в случае возникновения таковых.

Вот интересно, а если по какой-то причине оно зависло в каком-то конкретном состоянии по какой-то причине, то можно ли как-то протолкнуть дальше вручную?

Да, такие механизмы есть.
При оркестрации контекст FSM можно хранить, например в MongoDb (masstransit умеет так из коробки). Даже если сам оркестратор умрет, то можно будет продолжить с того места, откуда начали.

При хореографии можно надеятся только на стандартные иструменты с очередьми: DLQ, retry policy и т.п.

А сценарии сложнее линейной последовательности из нескольких шагов MassTransit в Saga научился обрабатывать? Условные переходы, параллельные задачи?

Сложность сценария зависит от задачи и разработчика, а не от библиотеки (особенно это касается хореографии).

Если, вы имеете ввиду, умеет ли такие возможности реализация FSM в Masstransit при оркестрации, то да.

Условия можно прописывать внутри блока When с помощью конструкции If.
Возможно я не понимаю, что вы имете ввиду о "параллейных задачах" в распределенной транзакции, но Вы можите в рамках одного State публиковать несколько разных собыйтий и они буду выполняться паралельно, плюсом masstransit поддерживает из коробки Schedule

и теперь необходимо уже отметить бронь и вернуть деньги пользователю.

отменить

Спасибо! Исправил

Sign up to leave a comment.

Articles