TransWikia.com

Event Sourcing/CQRS for Self-Related Entities

Software Engineering Asked by Alec Sanger on February 7, 2021

I’m building a platform that has an entity named content. There’s a clear boundary around what defines content except that it can have relationships with other content entities.

Up until now, there’s been no need to know anything about that related content until read-time, at which point my projections have taken care of the read requests.

I now have a requirement that certain commands should fail if the content has a related content with a certain state.

I’m considering using my projections at the time of the command to do a quick sanity check to validate the command and then use the saga pattern to do the real confirmation (at which point I can reverse the previous event if we find that it’s not actually valid). I’m having a hard time figuring out how to avoid race conditions for the hard validation down the line.

Imagine we have content-1, content-2, and content-3 streams.
Assume:

  • In order for any Content to be published, all related content must also be in a published state.
  • Content 1 has a relationship with Content 2 and Content 3 (this is a one-way relationship)
  • All content is currently unpublished.

Commands:

  • content-2, publishContent
    • This succeeds because Content 2 does not own the relationship to any other content.
  • content-3, publishContent
    • This succeeds because Content 3 does not own the relationship to any other content.
  • content-1, publishContent
    • This has to check Content-2 and Content-3 to confirm that they are in a published state.

How can I confirm that nothing has become unpublished between checking the state of Content 1 and the state of Content 2? Or between checking those states and persisting the event? I was thinking maybe I could let it go through if the initial checks pass and then do another check on any contentUnpublished events that make it through to revert the contentPublished that probably should have failed, but there’s no good way to determine the inverse of those relationships through my source of truth (the event store).

How can I implement this validation in a way that stays true to Event Sourcing and CQRS patterns?

One Answer

This is going to be quite difficult.

Your options would be to pessimistically lock the dependent streams when the command to publish the third stream occurs and unlock when it succeeds or optimistically do it and then post-command check with compensating events if that check shows a change.

In either case this means that whenever you get the state of the streams you need to return the "as of event #" so you can tell if anything has happened since that state was found.

I would also recommend having the steps of your command handler backed by its own event stream so you can see what the state of each check was as at the point you were deciding whether or not to allow publishing of stream-3.

Imagine that you are in room 302 in a hotel and you want to know how many people are in room 101. You can wander downstairs and look in the room, count the people and wander back...

However in the time it takes you to get back people may have entered or left the room. You might lock room 101 behind you so nobody can get in or out but then there is a risk that someone else needs to go into the room and they can't - until you unlock it again. This is considered bad.

Or you can return and say "as of when I was there, there were 2 people in room 101 but that might no longer be true" and whoever asked you to do that count has to deal with the fact that the information is out of date.

Dealing with the fact that the information is out of date is somewhat complicated and really does depend on what business action you are doing with this information.... this is where the analysis is needed.

Answered by Merrion on February 7, 2021

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP