Consistency of synchronous event handling when using optimistic locking to detect conflicting changes on aggregates

88 views
Skip to first unread message

paolo.ven...@gmail.com

unread,
Mar 8, 2017, 7:39:17 AM3/8/17
to DDD/CQRS
Hi all,
I'm wondering how to avoid undesired side effects (wrong view projections or undesired fire and forget interactions with external systems) that may occur during concurrent aggregate modification in separate transactions.
I'm using optimistic locking to detect conflicts when transaction is commited and event handlers are executed synchronously in the same transaction.

Scenario:
  1. Let's suppose that two parallel flows issue a command to the same aggregate. The former flow causes ThisOccured event propagation while the latter causes ThatOccured event propagation; 
  2. During the same transaction event listeners are triggered by events in order to update a real model;
  3. When the transactions are commited the optimistic locking strategy (based on aggregate versioning or last modification timestamp) will cause a failure, let's suppose that one in which ThisOccured event has been generated;
  4. At this point let's say that we have a conflict resolution strategy which considers wrong ThatOccured event and want to apply only ThisOccured event;
Questions:

In this scenario the projection based on ThisOccured event has been committed regardless the conflict detected when the latter transaction occured.

  1. How would you prevent this?
  2. Is it a conflict resolution strategy responsibility emit some compensating action to change the aggregate state previously described as ThatOccured event?
  3. Is it correct to suppose that the compensating action would cause a new projection on read model in order to correct the read model?
  4. What if the event handler interacts with a fire and forget external service such as a queue or a mail server?

Thanks for your support, best regards

    Paolo

Ramin

unread,
Mar 9, 2017, 2:30:25 AM3/9/17
to DDD/CQRS
Hi Paolo,

The domain/aggregate roots take care of invariants / consistency, projections don't. You can implement eventual consistency based on your read model / projections, but that is not what you seem to be describing here. You must always be able to build a read model off of the events, else there is something wrong with your denormalizers / projections and it must be fixed. This is true regardless if you build your projections synchronously or asynchronously.

It is possible to detect conflicts in the read model, which can be compensated in order to achieve eventual consistency. This topic has been discussed in detail. But a compensating action is something that your system will be prepared for, and it will be performed not because there is a failure when a projection is built, but after a projection has been succesfully built, and you detect that the read model has a state that needs compensation.

Cheers
Ramin
Reply all
Reply to author
Forward
0 new messages