w0051977
w0051977

Reputation: 15787

What is the relationship between 1) Domain Events and Transactional consistency and 2) Integration Events and Eventual consistency

I understand the difference between transactional consistency and eventual consistency. Say I am developing an application where there are three Microservices and there is a Message Bus, which sends messages between them when Integration Events are raised meaning eventual consistency. For example, Microservice B publishes an integration event and Microservice A handles it two hours later because Microservice B was down at the time the event was published and the message is durable - this is fine.

The way I understand it; there should be transactional consistency inside a Microservice - Aggregate A may publish a domain event that Aggregate B is interested in so a Domain Event is raised and any updates to the database are performed within the same transaction.

I do not understand how CQRS fits into this transactional consistency/eventual consistency scenario because:

  1. I cannot use transactional consistency because the read model (NoSQL) and write model (SQL server) cannot be updated inside the same transaction.
  2. I cannot use the Message Bus because updating the read model is not an integration event i.e. the read model and write model are contained inside the same Microservice.

With CQRS I believe there are two options:

  1. If using Event Store for the write side, then the read side can poll it - this solves the problem because there is no event.
  2. If using an Event Log/relational database for the write side, then a Domain event is raised to update the read side.

If option two is chosen then how can I guarantee that the read model will be in sync with the write model eventually? For example, the read model may be down when the event is raised.

Upvotes: 1

Views: 742

Answers (3)

choquero70
choquero70

Reputation: 4754

If option two is chosen then how can I guarantee that the read model will be in sync with the write model eventually?

The solution is a mix of your two options:

  • Raise a domain event when executing a command.

  • Store the domain event in an event store in the write model. This task is perrformed by a static lightweight subscriber. The event is stored in the same transaction that the command is executed.

  • A worker or batch process takes the events of event store and send them through a message queue.

  • A subscriber takes them from the queue and updates the read model.

This way you never lose events. If the read model isn't available for whatever reason, the worker will rethrougj the event again.

Upvotes: 0

aschuell
aschuell

Reputation: 101

Technically an aggregate IS the unit of atomicity in DDD, so there doesn't need to be a guaranteed of consistency between aggregates communicating via domain events. From Evan's book:

An AGGREGATE is a cluster of associated objects that we treat as a unit for the purpose of data changes ... Invariants, which are consistency rules that must be maintained whenever data changes, will involve relationships between members of the AGGREGATE. Any rule that spans AGGREGATES will not be expected to be up-to-date at all times ... But the invariants applied within an AGGREGATE will be enforced with the completion of each transaction.

For practical purposes, however, most of the services I've developed do wrap the processing of domain events in the same ambient transaction created to handle the processing of the initial request. Distributed applications are hard enough to design and debug without worrying about things like compensating actions inside a service!

I'm currently using the MediatR library to decouple the domain event handlers from the original command/request handler that generates them. It has very similar send/handle semantics to messaging systems, and include a robust middleware-like pipeline for validation and pre-/post-processing.

Upvotes: 3

Allan Chua
Allan Chua

Reputation: 10175

CQRS fits into the concept of eventual consistency by giving you lower vulnerability against optimistic locks when using DBMS systems for your read-only systems. Separating your commands and queries enables you to have a working read/write regardless of either's availability.

1). Transactional consistency is not advisable if you want to have highly available endpoints because of optimistic locking.

2). You can definitely use a message bus for updating you read models since the concept of queueing is not synonymous to inter-context data synchronization.

Upvotes: 2

Related Questions