I'm currently working on this use case :
- a budget is assigned to an organization unit
- Mike orders a good using the budget
- Jane gives its OK to this order, validate it. This actions triggers theses consequences :
- check budget balance to see if we can accept this order : inc ase of failure, notify Jane.
- budget is reduced up to the order amount
- order status changed from WAITING_VALIDATION to VALIDATED
- A success message is displayed to Jane
Additional usecase informations :
- for our users, the steps from 3.1 to 3.4 must be real-time. Jane clicks the button and waits for the answers : OK or NOT OK AND order status is VALIDATED
I'm thinking about :
- budget is a bounded context.
- ordering is another bounded context.
- the validation step will change 2 aggregate roots which seems wrong. And add coupling. If we need to update another aggregate root at the same time (step 3, like creating an accounting depreciation entry for the good).
- to be real-time, we can use an XA Transaction (SQL + Messaging for example) but I would like to avoid it (moreover my current technology stack doesn't allow me to use XA Transactions).
It seems that we can achieve this kind of usecase using eventual consistency : - Ordering service ask Budget service to handle a processOrder command (via messaging or REST) : at this point Ordering service is waiting for the Budget Service. - Budget Service handle the command (in a local transaction) and send OK / NOK to the caller - Budget service also send an OrderInBudgetProcessed event. - Ordering Service receives in realtime the OK / NOK and notify Jane (but the order status is not changed at this time) - Ordering Service handle the OrderInBudgetProcessed and update the order status in a local transaction.
I think this can works. However I have some issues :
- during the time where the order status is not updated, Jane can't print the order to send it to the supplier.
- during the time where the order status is not updated, we can imagine that Mike want to cancel the order. The status is still WAITING so the action "Cancel" is allowed. Must we ask the BudgetService that the order was already processed ? If yes, so we must ask all the services using orders their state. We can use something like a saga or coordinator ?
- putting compensation actions seems a lot of work ...
Some questions :
- The "order validation" - composed of 2 steps - is primarily handled by the budget context or the order context ? (seems to me that the main event is the budget diminution so I was thinking about the budget context). Seems logic to you ?
- what do you think of this kind of usecase ? too complex ?
- how do you handle this ?
- what do I miss to have at the same time a clean code (avoiding a service that update / synchronize all the objets in the same transaction) and a domain users (Mike / Jane) satisfied.
Please correct me where I'm wrong :)
Looking forward to hearing from you.
François