Search code examples
domain-driven-designsaga

Saga, where to store aggregate status


I'm new to saga.

Here a simple scenario :

  1. User click "Create Order" : an order is created (holding its state = NEW at first)
  2. Once the user has finished filling the order, click SAVE --> state is now SUBMITTED
  3. When another check the order and VALIDATE it, then a process must occur. The order is VALIDATED only if some others services are called and give their GO.

The whole workflow is :

  • NEW-> SUBMITTED.
  • From SUBMITTED the user can cancel is submission and the order switch back to NEW.
  • The validation can either set the Order status to VALIDATED or REJECTED.
  • If REJECTED the orginal user must fix his order before put it to VALIDATION again.

So I need to avoid that the order can rollback to NEW when a VALIDATION is in progress.

My question is, for step 3, is it better to :

  • update the state of the order to PENDING, raise an event and start a saga (with its own state and the orchestration of the process and the routine slip) ?
  • remove the state from the order aggregate and put it into the saga (so the saga starts at step 1) ? the saga is named OrderSaga and encapsulates all the process from start to finish and not only the parts where external services are needed, i.e distributed transaction).
  • something else ? (links to blog or google group mail appreciated)

thanks


Solution

  • DDD is about the domain so first you need understand the business needs. So, let's see what are the rules:

    1. A new order can be created
    2. A created order can be submited but after it is validated
    3. The validation process could take some time and it can be canceled. If it is canceled the order can be submited again
    4. The validation process could either reject the order or accept the order
    5. If the order is rejected it can be submitted again after is corrected
    6. If the order is accepted it is sent to the next process and it cannot be submitted or corrected.

    That being said, I would keep separate the two processes (the order creation+creation and the order validation). Also I would keep a status property on the OrderAggregate that is being used to enforce its invariants. The status can be:

    1. new: after the order is created or the validation is canceled or order is rejected
    2. submitted: after it is submitted for validation
    3. sent: after it is accepted by the validation process.

    You should add new states only if you need aditional behavior.

    The OrderValidationSaga would also have an internal status used to keep track of the external responses received from the external services. Let's suppose that we need to use two external services. The status would be an object with two properties: service1IsOk and service2IsOk. When any of the services says that the order is invalid then the saga rejects the order regardless of the internal progress and it resets its internal state. When a service says OK then the saga mark it internally as OK then it checks if all the services are OK. If they are OK it tells the aggregate to send the order. Then the aggregate marks the order as sent and emits an event. If/when the process is canceled, the saga resets its internal state.

    Note that if you use CQRS then all the status changing are done by sending commands and raising events. The saga would subscribe to events and send the appropriate commands to the aggregate.

    There is a fine article here.