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?