2014-09-30 1 views
1

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

  1. Команда отправляется клиентом и получил в HTTP конечной ChangePersonLanguage
  2. Команда отправляется и обрабатывается ChangePersonLanguageCommandHandler
  3. Внутри обработчика команды мы инкапсулировать бизнес-логику, поэтому мы загружаем корневой агрегат и выполнить метод Person.ChangeLanguage (язык)
  4. На данный момент PersonRootAggregate вызывает событие домена PersonLanguageChanged который содержит корень агрегатный объект
  5. Обработчик выполнить логику упорствовать агрегат и другой обработчик логика для отправки уведомлений по электронной почте

Правильно ли это? Могу ли я выполнить логику персистентности внутри обработчика команд и удалить один обработчик событий?

ответ

7

Да, вы должны выполнить логику сохранения состояния внутри обработчика команд, потому что:

  1. Вы можете повторно попытаться обработать команду, если сохранение не удается.
  2. Если команда принята, но персистенция терпит неудачу, вы можете столкнуться с серьезными проблемами после добавления в игру дополнительных обработчиков событий. Предположим, что эти другие обработчики событий реагируют на опубликованное событие и, следовательно, выполняют свои действия (например, sagas/long running бизнес-процесс и т. д.), но, с другой стороны, настойчивость действительно не удалась, и ваш агрегат находится в другом состоянии. Затем ваш AR и ваш оставшийся домен безвозвратно не синхронизируются.

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

  1. либо использование транзакций: сохранение изменений в той же транзакции, что и публикация событий. Это может потребовать XA-транзакции (2-фазные коммиты) в зависимости от вашей стойкости/шины сообщений и, следовательно, может быть дорогостоящим.
  2. опрос вашей базы данных о любых новых изменениях/событиях, которые должны быть опубликованы (опрос, естественно, означает некоторые дополнительные задержки)
  3. использовать магазин событий, который сочетает в себе сохранение и публикацию событий.
+0

Очень четкое объяснение, спасибо – Raffaeu

6

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

Основная причина, по которой не включает весь агрегат, заключается в том, чтобы отделить событие от объекта. Например, в сценарии DDD у вас может быть другой ограниченный контекст, прослушивающий это конкретное событие, и что ограниченный контекст имеет другое Агрегат для Лица, поскольку он может иметь дело со сложностью другого домена, такого как биллинг и т. Д.

Это означает, что абоненты не должны иметь зависимость от вашего конкретного агрегата.

+0

Большинство образцов, которые я нашел в книгах и статьях об этой концепции, отправляют всю совокупность корней в сообщении, но на самом деле вы правы, с точки зрения памяти, отправляющей весь агрегат, вместо того, чтобы сказать «Эй посмотрите, это идентификатор Лица, и это идентификатор нового языка »было бы более удобным. IMHO – Raffaeu

+2

Основная причина не включать весь агрегат - это отделить событие от объекта. Например, в сценарии DDD у вас может быть другой ограниченный контекст, который прослушивает это конкретное событие и что ограниченный контекст имеет различный Агрегат для Лица, поскольку он может иметь дело со сложностью другого домена, например биллинга и т. Д. Это означает, что подписчики не нужно иметь зависимость от вашего конкретного агрегата. –

+0

. Простое правило состоит в том, чтобы всегда использовать (если возможно) собственные типы (строка, int, datetime и т. д.). Это заставляет вас разлагать/отображать ваше AR на ваше мероприятие, чтобы вы избегали того, что уже заявил Никлас Арбин. Ваши другие БК (которые, скорее всего, те, кто потребляет эти события), не должны знать других БП ВС. –