Я работаю над архитектурой микросервисного решения, в котором большая часть кода будет написана на C# и, скорее всего, на Angular для любого внешнего интерфейса. Мой вопрос касается цепочки сообщений. Я все еще выясняю, какой брокер сообщений использовать; Служебная шина Azure, RabbitMQ и т. д. Существует концепция, о которой я мало что нашел.

Как мне обрабатывать случаи, когда я хочу запустить сообщение, когда был запущен определенный набор сообщений. Пример, но не часть моего фактического решения: я хочу сказать «Уведомлять кого-то, когда оплачивает счет». Мы отправляем сообщение "PAIDBILL" который запустит микросервисы, которые будут обрабатываться независимо:

  1. FinanceService для дебетования бухгалтерской книги и увольнения "PaymentPosted"

  2. EmailService: электронное письмо, в котором клиент говорит спасибо за оплату счета "CustomerPaymentEmailSent"

  3. DiscountService: проверьте, получают ли они скидку за своевременную оплату, а затем отправьте "CustomerCanGetPaymentDiscount"

Если все три сообщения сработали для одного и того же PAIDBILL: Message "PaymentPosted", "CustomerPaymentEmailSent", "CustomerCanGetPaymentDiscount" затем я хочу сообщить клиенту по электронной почте, что он получит скидку на свой следующий счет. Это должно быть сделано ПОСЛЕ того, как все три сработали, и порядок не имеет значения. Как запланировать отправку нового сообщения "EmailNextTimeDiscount" сообщения, не опрашивая, какие сообщения отправляются каждую минуту, час, день?

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

0
greektreat 8 Ноя 2019 в 19:19

1 ответ

Если вы используете сообщения (например, Service Bus/RabbitMQ), то я думаю, что описанное вами решение является лучшим. Этот тип проектирования, при котором сервисы обладают знаниями о других областях системы, обычно называется хореографией.

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

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

  1. PAYBILL заставляет FinanceService дебетовать бухгалтерскую книгу и запускать «PaymentPosted»
  2. «PayentPosted» заставляет EmailService отправлять электронное письмо клиенту с благодарностью за оплату счета и транслирует «CustomerPaymentEmailSent»
  3. «CustomerPaymentEmailSent» заставляет DicsountService проверять, получают ли они скидку за своевременную оплату, а затем отправляет «CustomerCanGetPaymentDiscount».
  4. Электронное письмо, которое вы хотите отправить, просто инициируется «CustomerCanGetPaymentDiscount».

Если честно, я бы поменял модель зависимости, которую вы используете на этом последнем этапе. Таким образом, вместо того, чтобы какой-либо компонент прослушивал события «CustomerCanGetPaymentDiscount» от DiscountService и отправлял электронное письмо, я думаю, что вместо этого DiscountService сказал бы другому компоненту отправить электронное письмо. Мне кажется естественным, что что-то, что рассчитывает скидки, знает, что нужно отправить электронное письмо. Для того, кто отправляет электронные письма, кажется менее естественным знать о скидках (и обо всем остальном, что требует отправки электронных писем). Вот почему мне не нравятся архитектуры, в которых предполагается, что каждое сообщение должно быть событием, а каждое действие должно запускаться событием: это устраняет множество решений о том, где может жить логика предметной области, потому что получатель сообщения всегда должен знать о домене отправителя сообщения, а не наоборот.

1
Graham Lea 11 Ноя 2019 в 02:08
Этот пример не является тем, что я специально обрабатываю, это было теоретически, как часть моего дизайна, мне нужно иметь решение для любой ситуации, которая может быть основана на этом. Спасибо за определение, я не знал, что это называется хореография, что имеет смысл. Существует ли другая архитектура, которая может обрабатывать хореографию, отличную от сообщений?
 – 
greektreat
15 Ноя 2019 в 17:57
Теоретически вы могли бы выполнить хореографию, используя синхронный обмен сообщениями, но это было бы нетипично, особенно потому, что синхронные сообщения чаще используются для команд, где A говорит B что-то сделать, чем для событий, когда B слушает A, чтобы посоветовать завершить чего-либо. (Веб-перехватчики являются очевидным исключением из этого правила из-за инверсии управления.) И вообще, как только архитектура становится относительно большой, я советую отдавать предпочтение асинхронным связям, где это возможно, чтобы ограничить временную связь.
 – 
Graham Lea
16 Ноя 2019 в 13:10
Если вы хотите избежать обмена сообщениями в пользу синхронного общения, вы можете рассмотреть альтернативу хореографии — оркестровку. Думайте о хореографии как о наборе полуслабо связанных сервисов, взаимодействующих друг с другом для достижения цели, большей, чем любой из них осознает. Вместо этого при оркестровке отдельные службы более слабо связаны друг с другом, но существует централизованная служба, которая управляет этапами рабочего процесса. Эта служба понимает и стремится к достижению всей большей цели.
 – 
Graham Lea
16 Ноя 2019 в 13:14