Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should domain events be raised within or outside of a transaction?

Tags:

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?

like image 901
Andronicus Avatar asked Jan 14 '11 13:01

Andronicus


People also ask

How do you handle domain events?

Handling the domain events is an application concern. The domain model layer should only focus on the domain logic—things that a domain expert would understand, not application infrastructure like handlers and side-effect persistence actions using repositories.

What is a domain event in DDD?

In domain-driven design, domain events are described as something that happens in the domain and is important to domain experts. Such events typically occur regardless of whether or to what extent the domain is implemented in a software system. They are also independent of technologies.


2 Answers

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.

like image 173
Szymon Pobiega Avatar answered Oct 06 '22 00:10

Szymon Pobiega


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.

like image 27
Miklos Csuka Avatar answered Oct 05 '22 23:10

Miklos Csuka