I'm currently playing with DDD & CQRS, and I moved forward a legacy application.
Let's say I have an Article entity, on which I can cast votes.
When a Vote is casted on an Article, I want to increment or decrement a counter accordingly to the value of the vote.
This counter is part of my Query model and thus I don't think it fits the Domain Model, for such reasons, I decided to write a CastArticleVoteService in which I put the business logic about a vote, and I dispatch an Event to be handle by a custom Event Handler which in turns update the counter in a database.
First of all, I was skeptical because I told myself "hey, the process of updating the counter should be in the same transaction as the one which persist the data". But that's obviously wrong if I have polyglot persistence (ie: MySQL / Redis).
However, the transaction stills apply, how could I be sure that the whole event handlers are processed properly and my data are consistent? (here my counter). (what about asynchronous events handler?)
Any tips?
Alright, here is my take on your question:
In event driven
& CRQS
architecture, it is also common to use event sourcing
as a pattern.
That means that your votes will not be stored as a counter (state
), but rather as vote up/down (fact
).
In your scenario, to query how many votes an article have accumulated, you can go read all the events related to an aggregate and apply them one by one (in memory) in the order they happened and get a final state of that aggregate instance (article
).
Sometimes when the volume of events are big, a snapshot is kept on the most recent facts resulting from applying those events to an aggregate.
Worth noting: Be careful of side-effects when applying events to get state. Because if a vote up/down event caused an article to be closed for example and sent an email to the author, then you don't want that email to be sent again when replaying those events.
Think of this as the financial equivalent to debit/credit events in a bank. Banks don't just store your balance. They actually store all your transactions, and later do a reconciliation and update your balance.
Some transactions happen immediately if the debtor/creditor accounts are within the same bank
What that gives you out of the box?
- Scalability; this is a write-optimised architecture that can handle larger requests to modify application state faster without transactions & locking
- Traceability; when inspecting your system, not only you will find out where you're at (current state) but also you will know how/why you got there (events)
Also, since you have a data stream of all user interactions with the system, you can later use that data in different ways for new features that you would not have thought of from the beginning of designing the system (Analytics for example?)
Further reading:
Aggregates define transaction boundaries. When you decide for event-driven architecture then you decide for eventual consistency. So you just have to choose: transaction OR event.
Note that in most cases, eventual consistency is completely fine for the business. That's only devs who have a transactional fetish implanted by RDBMS lectures/brainwash on the university ;)
来源:https://stackoverflow.com/questions/22168363/how-to-handle-transaction-in-event-driven-architecture