Reputation: 15787
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:
With CQRS I believe there are two options:
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
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
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
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