Question

In our application we raise domain events when something changes in the domain model. Some of the tasks that are performed by the event handlers must be done within the same transaction that was used when the event is raised, other tasks must be performed outside of this transaction.

For example,

When an Orderline is added to an Order entity, the OrderLineAdded domain event is raised, one domain event changes the state of the domain model (so must be performed in the same transaction), then when the transaction is completed the UI must be updated.

How would you approach this problem?

  1. Raise two events, one inside the transaction, and one outside of the transaction.
  2. Raise the event inside of the transaction, but use the event handler to send an Async request to update the UI?

Option 1 seems confusing, since the events names must somehow convey they are in or out of a transaction, but with option 2 handlers of the domain event must always assume that they are called synchronously from within a transaction.

Maybe there is a better approach?

Was it helpful?

Solution

I've had a similar problem. Domain model was publishing events (using the technique Udi Dahan describes here). Then I realized that my UI-related handlers are invoked even if something goes wrong and transaction is rolled back later.

To fix this I introduced another role to the system, another kind of event handler. I has ITransactionalEventHadneler and INonTransactionalEventHandler. The former were invoked synchonously immediately in DomainEvents.Publish() method. The latter were queued to be invoked as soon as transaction gets committed (using System.Transactions hooks). The solution worked fine and was quite readable and maintainable.

OTHER TIPS

I think both approach could be good, just stick to the same approach in every part of your code:

  1. you'll need two (or more) event handlers, one for the context of the domain model that's inside the transaction scope and other(s) for the auxiliary contexts, like the UI. Your domain code should not care about what other parts of the code do, just notify them about the change in the domain data.
  2. your domain code event handler method may send asynchronous events to the UI or other modules. The domain events should be synchronous, otherwise you'd need two-phase commits to keep transactionality.

I personally like option 2 more, because it keeps the domain code cleaner and by using asynchronous communication the core and other modules will be decoupled, therefore problems in the external modules will not hinder the workings of the core. On the other hand, there may be circumstances where option 1 is more advantageous.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top