CQRS - может ли EventListener вызывать Command?

Я хочу использовать элементы шаблона CQRS в моем проекте. Интересно, правильно ли я это делаю с Командой и Событиями. Я не уверен, что событие может вызвать команду. Чтобы лучше показать, что я хочу сделать, я буду использовать диаграмму и пример.

Это пример:

Пользователь вызывает TripCreateCommand. TripCreateCommandHandler выполняет свою работу и после успеха публикует TripCreatedEvent.

Теперь у нас есть два слушателя TripCreatedEvent (порядок выполнения слушателя не имеет значения)

Первый слушатель (может быть выполнен после второго слушателя):

для каждого пользователя в trip.author.friends вызывайте две команды (порядок команд важен)

  1. PublishTripOnUserWallCommand
  2. SendNewTripEmailNotificationCommand
  3. SendNewTripPlatformNotification

Второй слушатель (может быть выполнен перед первым слушателем):

  1. PublishTripOnUserSocials

И это пример диаграммы:

Это хороший способ? Может ли EventListener вызывать Command, или, может быть, я должен сделать это другим способом?

2 ответа

Решение

Ваш вопрос касается Mesage Driven Architecture, которая работает вместе с CQRS, но никак не связана с ней.

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

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

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

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

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

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

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

Отправка электронного письма может рассматриваться как команда, но ее также легко можно рассматривать как очередное обновление модели представления.

Не ясно, какова цель SendNewTripPlatformNotification, поэтому я не могу дать какие-либо предложения там...

Кое-что из этого также может быть кандидатом в саги. Во-вторых, мне не хватает вашего Домена на диаграмме, то есть что должно отвечать за публикацию каких-либо событий, или вы считаете CommandHandler Доменом?

Другие вопросы по тегам