Search code examples
domain-driven-designevent-sourcingsaga

Multi-Aggregate Transaction in EventSourcing


I'm new to event sourcing, but for our current project I consider it as a very promising option, mostly because of the audit trail.

One thing I'm not 100% happy with is the lack of aggregate-spanning transcations. Please consider the following problem:

I have an order which is processed at various machines at different stations. And we have containers where workers put the order in and carry it from machine to machine.

The tracking must be done through containers (which have a unique barcode-id), the order itself is not identifiable. The problem is: the containers are reused and need to be locked, so no worker can put two orders in the same container at the same time (for simplicity just assume they can't see if there is already an order inside the container).

For clarity, a high level view:

  • Order A created
  • Order A put on Container 1
  • Container 1 moves to Machine A and gets scanned
  • Machine A generates some events for Order A
  • Move Order A from Container 1 to Container 2
  • Order B created
  • Order B put on Container 1 ...

"Move Order A from Container 1 to Container 2" is what I'm struggling with.

This is what should happen in a transaction (which do not exist):

  1. Container 2: LockAquiredEvent
  2. Order A: PositionChangedEvent
  3. Container 1: LockReleasedEvent

If the app crashes after position 1 or position 2, we have containers that are locked and can't be reused.

I have multiple possible solutions in mind, but I'm not sure if there is a more elegant one:

  • Assume that it won't fail more than once a week and provide a way the workers can manually fix it.
  • See the container tracking as a different domain and don't use event sourcing in that domain.
  • Implement a saga with compensation actions and stuff.

Is there anything else I can do?

I think the saga-thing is the way to go, but we will have a rest api where we get a command transfer order A from container 1 to 2 and this would mean that the API command handler would need to listen to the event stream and wait for some saga generated event to deliver a 200 to the requester. I don't think this is good design, is it?

Not using event sourcing for the tracking is also not perfect because the containers might have an influence on the quality for the order, so the order must track the used containers, too.

Thank you for any hints.


Solution

  • The consistency between aggregates is eventual, meaning it could easily be that AR1 changed its state, Ar2 failed to change its state, and now you should revert the state of AR1 back to bring system into a consistent state. 1) If such scenarios are happening very often and recovery is really painful, rething your AR boundaries. 2) Recover manually. Don't use saga's, they should not be used for such purpose. If your saga wants to compensate AR1 but other transaction already changed its state to another one compensation would fail.