eventflow / EventFlow

Async/await first CQRS+ES and DDD framework for .NET
https://geteventflow.net
Other
2.38k stars 446 forks source link

Exception in read model does not roll back event creation but classes implementing ISubscribeSynchronousToAll do not receive event #833

Closed alasdair-stark-screenmedia closed 1 year ago

alasdair-stark-screenmedia commented 3 years ago

We publish all events to event grid using a custom class that implements ISubscribeSynchronousToAll.

We have a read model which subscribes to a specific type of event. The SQL Server table behind the read model has a column called 'Name' that has a limit of 100 chracters. Consider the following sequence of events:

  1. Aggregate emits event that contains a name that is 150 character long
  2. Read model handles event and attempts to create the record
  3. INSERT fails due to truncation and causes an exception to bubble up

When this happens we see that the event has been written to the EventFlow table. However, our event grid subscriber never receives the event.

What is the recommended way to handle exception in read models?

If failure to update a read model prevents events from reaching classes that implement ISubscribeSynchronousToAll then shouldn't the system roll everything back? For consistency I would expect the event to be removed from the EventFlow table and any other changes to read models to be rolled back.

Herlitzd commented 3 years ago

Just for clarity, the problem isn't really anything to do missing validation, or fields lengths, that could be fixed by truncating in your readmodel, or adding validation before executing the command. We have noticed the same behavior you are describing when a SQL user lost permissions to write to the ReadModel table, we saw that the failure to persist the SQL readmodel was logged, but the SynchronousSubscriber never received the event. And to your point, the event-store, and other readmodels were updated.

Definitely seems like this is not the expected behaviour, we would be fine with the readmodel not persisting, and logging, but the subscriber MUST fire whenever the event is persisted to the EventStore.

alasdair-stark-screenmedia commented 3 years ago

Yes, I just wanted to provide an example to illustrate the issue. If an exception is thrown for any reason during the processing of the read model then this issue will occur.

dthk-cogmatix commented 3 years ago

Outsider observation:

This may be due to a larger design problem that is concealed within the framework. I don’t even know if you could classify it as a bug, but a consequence of the current implementation. I’m not bashing EventFlow, as I don’t think any framework really has this solved, and EventFlow has provided a great starting point to start focusing on solving the problem at hand and not rolling out a bunch of boiler infrastructure code. This is just a caveat emptor.

Example: If I have a Command to update an aggregate, that is successful, and now I have an event fired to Read Model or Subscribers, I’ve basically created a distributed system problem: How do I persist across transactional boundaries.

Transactional Boundaries: Aggregate stored in Event Store Read Model is ElasticSearch Read Model in MongoDB

Because you have updates occurring across different databases, you really can’t leverage a Unit of Work and wrap it all in a transaction. There isn’t any persisted state being managed for events at the framework level to handle resiliency (all uses of buses are for integration purposes). Fundamentally, to do what you want, would require a departure of what is encouraged within EventFlow and the out of box implementations of Read Models. To solve for this, top of mind thoughts are: you would need to either decompose your write and read into isolated pieces and use something more resilient to glue them together (Service Bus), Implement a Saga/Process manager to maintain state and coordinate activities to update read models (assuming the Saga + Aggregate update would be in one unit of work), or some sort of outbox pattern and use Hangfire to pickup the work. Definitely a lot more plumbing to deal with and detracts from the easy out of the box offerings from EventFlow to do some of this stuff.

I was about to dive in and implement Event Flow, but after being aware of this gotcha and reading the source code, this may not be the silver bullet for MY needs, but it may be for yours.

CentinelaBot commented 3 years ago

@alasdair-stark-screenmedia It seems to be a problem of eventual validation of consistent data.

I'll pass you a url on the issue you raise.

Eventual Consistency

github-actions[bot] commented 1 year ago

Hello there!

We hope you are doing well. We noticed that this issue has not seen any activity in the past 90 days. We consider this issue to be stale and will be closing it within the next seven days.

If you still require assistance with this issue, please feel free to reopen it or create a new issue.

Thank you for your understanding and cooperation.

Best regards, EventFlow

github-actions[bot] commented 1 year ago

Hello there!

This issue has been closed due to inactivity for seven days. If you believe this issue still needs attention, please feel free to open a new issue or comment on this one to request its reopening.

Thank you for your contribution to this repository.

Best regards, EventFlow