I have three aggregates Product, Seller, Buyer. The buyer offers to buy a product from the seller and the seller can accept or reject the buy offer. So the process for making the offer is this: in the buyer aggregate I check whether the buyer has already made offer too the product, then I check in the product aggregate if its status is in sale and check in the seller aggregate if the buyer is banned (the seller aggregate has list with banned users). If all checks are true the saga create new offer. But what if after I have checked whether the buyer is banned the buyer gets banned? The seller will ban a user and after that he can still receive an offer from the user?
Races are an inevitable consequence of designing a system with distributed decision making authority.
In other words, it takes time for the information that a particular shopper is banned to travel from the shopkeeper who made the decision to the centralized model. So in just the same way that we have to handle the case where we send an offer to the shop nanoseconds before the shop bans the shopper, so to do we need to handle the case where we send an offer in the nanoseconds between when the shop bans the shopper and when that information gets integrated into the domain model.
This is part of the tradeoff we accepted when we chose a distributed system in the first place.
As far as I can tell, we manage this mainly by setting expectations. "Bans shall be announced five minutes before they take effect", or whatever, to give the information time to move around your system.
Expectation setting might use the language of service levels (99% of all bans are effective within five minutes).
Mostly, you're going to be managing tradeoffs - how important is respecting a recent ban compared to expediting the delivery of offers? If you don't need low latency delivery, then you can afford to wait a little while to see if a ban shows up.
(If you'll look carefully, you'll see that there is still a race condition present - what we're really manipulating is the business significance of the race. See Udi Dahan's Race Conditions Don't Exist)
In a local setting, if you really need tight control of the sequence of bans and offers, then you need to have a single lock in the system shared by the code that processes bans for a particular shop and the code that processes offers for a particular shop.
That doesn't prevent the race, of course (you get different behaviors depending on whether ban acquires the lock nanoseconds before the offer or nanoseconds after), but does at least give you a clear "happens-before" relationship in your audit log.