I am currently struggling in how to ensure that aggregates are eventually consistent in the case that an aggregate does not exist
Lets take I have a order service that deals with creating me an order of products and I have a product service that manages those products
I have two aggregates that are distributed over multiple services and lets say I add product to the order, I would create a command that would create an event to set up the order and one to add the product, what happens tho if the Id provided to the order for the Product does not exist?
// What I have tried
I did think I could send an event to say that the product does not exist after it was added to the order and this in turn would resolve the issue, however, as far as I am aware I would need to create an event based on an aggregate but the Product service would not have an aggregate based on that Id
The other way I thought was to say from order I would tigger and event that say ProductRequestedForOrder, then if the product service has the aggregate it would fire a event to state it exists and then the order service would create another event saying ProductAddedToOrder
I appreciate any help you can provide, thank you
What should happen, at a business level? That's the first thing you need to figure out. Maybe the business wants to reject the order; or maybe they want to accept the order, even though it isn't obvious that it can be fulfilled. Maybe the order should be treated as a draft, permitting error correction by the customer.
Because you have distributed product information from order information (ie, because you can't lock products while working on orders), there's always going to be a bit of latency between a change in Products and that change being visible to Order processing.
And that's always going to mean that there is some possibility that the handling of an order is inconsistent with some unscheduled change made to the product catalog.
If that's a show stopper, then you just can't design a system that treats this information in a distributed fashion.
If it's not a show stopper, then you are really just trying to design a solution that correctly balances the cost of delayed reconciliation against your other considerations.
Broadly, you're going to end up with Ordering having a locally cached copy of the Product information that it needs, and using that local copy in its own business logic. Then you need only discover the right caching policy to use (do we try to refresh the cache for each order? can we re-use our old data if the product catalog isn't available? do we need to stop processing orders if the product information we have is too old? and so on).
Recommended reading: Race Conditions Don't Exist (Udi Dahan, 2010)