Должны ли события домена вызываться внутри или вне транзакции? - PullRequest
19 голосов
/ 14 января 2011

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

Например,

Когда Orderline добавляется к сущности Order, возникает событие домена OrderLineAdded, одно событие домена изменяет состояние модели домена (поэтому должно выполняться в той же транзакции), затем, когда транзакция завершена, пользовательский интерфейс должен бытьобновлено.

Как бы вы подошли к этой проблеме?

  1. Создайте два события, одно внутри транзакции, а другое снаружи транзакции.
  2. Создайте событие внутритранзакции, но использовать обработчик событий для отправки асинхронного запроса на обновление пользовательского интерфейса?

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

Может быть, есть лучший подход?

Ответы [ 2 ]

17 голосов
/ 17 января 2011

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

Чтобы исправить это, я ввел в систему другую роль, другой тип обработчика событий.У меня есть ITransactionalEventHadneler и INonTransactionalEventHandler.Первые были вызваны синхронно сразу по методу DomainEvents.Publish().Последние были поставлены в очередь для вызова, как только транзакция будет зафиксирована (с использованием хуков System.Transactions).Решение работало нормально и было вполне читабельным и обслуживаемым.

1 голос
/ 17 января 2011

Я думаю, что оба подхода могут быть хорошими, просто придерживайтесь одного и того же подхода в каждой части вашего кода:

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

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

...