Domain Events

405 views
Skip to first unread message

Eusebiu Gagea

unread,
May 11, 2021, 3:01:07 PM5/11/21
to DDD/CQRS
Hello everyone! I need some help to wrap my head against some concepts. So far, I understood what Domain Events are. What I want know is I want to publish some Domain Events, react to them and make changes (maybe the handlers could publish more Events), but also publish some Events to another BC. The latter one should be processed out-of-proc. An ideal example would be something like this:

      CreateUserCommand -> CreateUserCommandHandler -> some code here -> UserCreatedEventPrivateDomainEvent and  UserCreatedEventPublicDomainEvent
      UserCreatedEventPrivateDomainEvent -> UserCreatedEventHandlerInsideThisBC -> AssignDefaultToUserCommand ->  AssignDefaultToUserCommandHandler
      UserCreatedEventPublicDomainEvent -> UserCreatedEventHandlerInsideNotifications -> SendConfirmationEmailCommand -> SendConfirmationEmailCommandHandler

     I saw some terminology like Private Domain Events (for those inside the current BC) and Public Domain Events. And the advice is to use Unit of Work and publish all Private Domain Events before committing the transaction and all Public ones after the commit phase. Makes perfect sense to me. In my case UserCreatedEvent is both Public and Private, so I created two events. The biggest concerc that I have is how I could implement the Unit of Work pattern here. For the first command, along with its event handlers that would be easy, but what if, like in the sequence above, an Event Handler send another Command? How do I know inside that command handler (here AssignDefaultToUserCommandHandler) that a transaction has already begun or I have to start it there?

Harrison Brown

unread,
May 11, 2021, 3:25:08 PM5/11/21
to 'Eusebiu Gagea' via DDD/CQRS

My team went over this issue a few times and the ‘ah-ha’ moment was when we realised we shouldn’t have our command handlers themselves be responsible for the unit of work themselves. Rather, we start a transaction in the unit of work and then run our command handlers. Then, in situations like yours where you want to react to ‘internal’ events (ie. those in the same BC) synchronously it’s simply a case of calling a command handler, then calling any event handlers which may themselves return further commands (i.e., the process manager pattern) and running those commands’ handlers within the same transaction. This way, no event handlers has to know whether ‘a transaction has already begun’ because they’re not responsible for the Unit of Work.

PS. You didn’t ask this, but another ‘ah-ha’ moment was when we realised that process managers (event handlers which may return commands in response) are part of our domain logic and thus should be part of our domain model. We actually go even further and make commands and command handlers part of the domain model too. The application/infrastructure layers are only responsible for taking commands from user input, or those returned from the domain model’s process managers, and passing them back to the domain model to execute by resolving the appropriate command handler.

This Twitter thread might be useful: https://twitter.com/mathiasverraes/status/1302233693021446150

--
You received this message because you are subscribed to the Google Groups "DDD/CQRS" group.
To unsubscribe from this group and stop receiving emails from it, send an email to dddcqrs+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/dddcqrs/8b5cd986-74bd-438e-9bee-923351cddca0n%40googlegroups.com.

Yordis Prieto

unread,
May 12, 2021, 3:35:36 AM5/12/21
to DDD/CQRS
Here is how I see the topic related to Domain Events and Events. Imagine for a moment we are just working in one domain (so a single context):

Your domain objects react to Events (not Domain Events), and your Command Handlers raise Events (Not Domain Events). So in other words:

Command ---  Sent To ---> Command Handler
Command Handler --- Apply Events ---> Aggregate
Command Handler --- Save Events ---> Event Store

In some cases, the same Domain needs to subscribe to some events, therefore.

Event Store ----- Publish Events -----> Event Handlers

Notice that so far I haven't use Domain Events, and we are still in the same domain as I said before.

So what are domain events for me?

Well, at some point you want to expose your events to the outside of your domain those are Domain Events, in other words, you don't rely on the events written to the Event Store for integrating with the domain. Except that most people do at the beginning for simplicity.

So, how it "suppose" to be done then when I need external domains to react to my Domain Events?

Event Store ----- Publish -----> Events -----> Event Handlers ----- Publish Domain Events -----> The External Bus

This is done by adding some anti-corruption layer between your Events and Domain Events to benefits from breaking the outside world at the cost of complexity, or tedious work.

So, does that means I would have `UserCreatedEvent` And `UserCreatedDomainEvent`: yes, if you want external domains and systems to consume such an event, and you want to add some anti-corruption layer.

I hope this makes sense, and also, this is my take on it, take it for what its worth it.

Nik

unread,
May 12, 2021, 3:38:59 AM5/12/21
to DDD/CQRS
Some people name them "Domain Events" for the ones within a BC and "Integration Events" for events going out of the BC via an event bus.

How I do it:

- Command handler processes a single request (command).
- Domain model generates domain events
- Prior to saving changes to the database and committing the transaction, domain events are dispatched and processed by domain-event-handlers.
- Those handlers may generate additional events
- After handlers have finished, any existing integration events are added to the Outbox (outbox pattern)
- Whole transaction is committed which includes all changes done in previous steps + the outbox
- If the transaction succeeds another process will fetch the integration events from the outbox and publish them to the event bus
- If the transaction fails, no data will be updated in the database and no integration events will be published

Harrison Brown

unread,
May 12, 2021, 3:59:02 AM5/12/21
to ddd...@googlegroups.com
Verraes has some nice articles on this topic: https://verraes.net/2019/05/patterns-for-decoupling-distsys-explicit-public-events/

Harrison

Sent from my iPhone

On 12 May 2021, at 08:35, Yordis Prieto <yordis...@gmail.com> wrote:

Here is how I see the topic related to Domain Events and Events. Imagine for a moment we are just working in one domain (so a single context):

Nik

unread,
May 12, 2021, 4:20:11 AM5/12/21
to DDD/CQRS
Please note, I see now it's a ES related question, where my answer is not.
Reply all
Reply to author
Forward
0 new messages