Raffaeu
Raffaeu

Reputation: 6973

CQRS relationship between Domain Command and Events

I am working on a CQRS architecture. Right now we have all the pieces in place and we handle a command following this flow:

  1. A command is sent by the client and received into the HTTP endpoint ChangePersonLanguage
  2. The command is dispatched and handled by ChangePersonLanguageCommandHandler
  3. Inside the command handler we encapsulate the business logic so we load the root aggregate and execute the method Person.ChangeLanguage(language)
  4. At this point the PersonRootAggregate raise a domain event PersonLanguageChanged which contains the root aggregate object
  5. An event handler execute the logic to persist the aggregate and another handler the logic to send out a notification email

Is this the correct order? Can I execute the persistence logic inside the command handler and remove one event handler?

Upvotes: 1

Views: 896

Answers (2)

Niklas Arbin
Niklas Arbin

Reputation: 692

As a sidenote the PersonLanguageChanged event should not contain the root aggregate, but rather just contain the information about what was changed.

The primary reason for not including the entire aggregate is to separate the event from the entity. For instance in a DDD scenario you might have another bounded context listening to this particular event and that bounded context has a different Aggregate for Person, since it might deal with the complexity of another domain such as billing etc.

This means that subscribers to not need to have a dependency to your specific aggregate.

Upvotes: 8

Alexander Langer
Alexander Langer

Reputation: 2893

Yes, you must execute the persistence logic inside the command handler, because:

  1. You might want to re-try to handle the command if persistence fails.
  2. If the command is accepted but the persistence fails, you might run into serious problems once you add more event handlers into the game: Suppose those other event handlers react to the event published and therefore execute their actions (say sagas/long running business process etc), but on the other hand the persistence actually failed and your aggregate is in a different state. Then your AR and your remaining domain are irrecoverably out of sync.

You must therefore make sure that your aggregates are persisted to the database before the events are published. For, you can

  1. either use transactions: persist the changes in the same transaction as the event publishing. This might require XA-transactions (2-phase-commits) depending on your persistence/message bus and might therefore be expensive.
  2. poll your database for any new changes/events that are to be published (polling naturally means some additional delays)
  3. use an event store that combines persistence and event publishing.

Upvotes: 8

Related Questions