Один агрегат на транзакцию с "одним" или "несколькими" ограниченными контекстами. - PullRequest
1 голос
/ 05 мая 2020

Следуя рекомендации Вона Вернона, для достижения высокого уровня разделения и единой ответственности, для каждой транзакции следует изменять только один агрегат.

В главе 8 Красной книги Вон Вернон продемонстрировал, как два агрегата могут «разговаривать» друг с другом с помощью доменных событий. В главе 13 рассказывается, как разные агрегаты в двух разных ограниченных контекстах могут «общаться» друг с другом с помощью уведомлений.

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

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

1 Ответ

1 голос
/ 06 мая 2020

Я вижу два аспекта, которые следует учитывать в вашем вопросе:

  1. Аспект DDD: типы событий и то, что вы с ними делаете

  2. Технический аспект: как его надежно реализовать

Что касается типов событий, я бы сказал, что события, которые обычно остаются в границах ограниченного контекста (часто называемые событиями домена) несут много информации. Потенциально большая часть состояния Агрегата. Если вы используете CQRS, они используются для создания модели чтения. События, которые пересекают границы B C, иногда называют событиями интеграции, и они должны нести как можно меньше данных (потенциально, только глобальные идентификаторы, такие как CustomerId, OrderId). Причина в том, что каждое дополнительное свойство, которое вы добавляете, является дополнительной связью между издателем B C и BC подписчика, что вы хотите минимизировать.

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

Предлагаемое вами решение правильное. Он очень похож на функцию Outbox в NServiceBus , которая в основном заботится обо всем этом за вас.

Другой подход, который я использовал, если ваш брокер сообщений поддерживает его, - это то, что Azure Service Bus вызывает Отправить через . С помощью этой функции вы можете публиковать sh событий через вашу собственную очередь, но отправка будет зафиксирована транзакционно с удалением входящего сообщения из очереди. Это означает, что если по какой-то причине обрабатываемое вами сообщение не было успешно удалено из очереди (исключение обновления БД, брокер недоступен и т. Д. c) и, следовательно, оно будет повторено, вы точно знаете, что события не будут будут отправлены, и вы можете безопасно опубликовать sh их снова во время повторной попытки. Это упрощает идемпотентные операции и позволяет избежать публикации фантомных сообщений.

...