Должны ли события домена вызываться внутри или вне транзакции?

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

Например,

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

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

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

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

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

2 ответа

Решение

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

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

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

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

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

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