EventSourcing внутри и снаружи ограниченного контекста

Я пытаюсь реализовать систему источников событий с помощью DDDD. В настоящее время я борюсь за то, как и где мои события пересекают границы ограниченного контекста.

Представьте, что есть два ограниченных контекста:

  1. Управление продуктом
  2. Система логистики

Управление продуктами обладает всеми знаниями о продуктах. Для упрощения это просто "Имя". Система логистики также имеет продукты, но не знает их метаданных. Для них это в основном только физическая коробка с идентификатором. Но когда кто-то сканирует этот продукт, он также хочет показать имя. Поэтому BC ProductManagement должен информировать BC логистики о том, что продукт зарегистрирован и имя изменилось. Итак, я закончу с событиями в ProductManagement, возникшими изнутри ProductAggregate:

ProductManagement.Events.ProductRegistered
ProductManagement.Events.ProductNameChanged

Когда я правильно понял, это события, которые я сохраню в хранилище событий. И это также события, которые будут опубликованы в шине сообщений. Так что на стороне логистики я подпишусь на эти события. Все идет нормально.

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

Я знаю, что нет никаких расчетов или изменений в агрегатах на стороне логистики. Но я думаю, что это не имеет значения для моих вопросов.

3 ответа

Пара вещей здесь.

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

Но в целом, это обычно работает так:

domain event -> pub/sub -> message consumer -> command -> domain command handler

Так,

  1. вы публикуете свое доменное событие на автобусе от PM BC
  2. в логистике есть обработчик этого события
  3. обработчик события может сделать некоторые проверки и отправить RegisterProduct командовать той же БК
  4. команда обрабатывается как обычно и новая Product агрегат создается в логистике

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

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

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

Кстати, эта серия постов в блоге описывает именно этот случай использования:

https://www.tigerteam.dk/2014/micro-services-its-not-only-the-size-that-matters-its-also-how-you-use-them-part-1/

(В части 5, если я правильно помню)

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

[...] Он также сказал, что было бы лучше преобразовать его в одну или несколько команд. Сохраню ли я все полученные события на стороне логистики? Я также сохраняю команды?

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

Как я могу воспроизвести свое текущее состояние, если что-то пошло не так? Или как я узнаю, что это не ошибка обработки в полученном ограниченном контексте, а скорее неправильное событие? Что я буду делать, если мои преобразованные команды будут отклонены?

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

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