I’m trying to to evaluate how an applications using event sourced aggregates can be scaled horizontally.
Imagine a typical scenario with one instance of an application:
Client broadcast command via the bus or gateway
Aggregate handles the command and it applies events internally
Events are applied and state is changed
Events are persisted (not too sure if this happens before the previous point)
Unit of work is committed and events are broadcasted to the outside world
Now I add a second instance of the application with some kind of load balancer on the command bus.
- Client sends the first request
- Load balancer sends it to the first node and all previous steps are completed
- The second node receives the event but the aggregate state is not updated because it can only be changed via commands
- Client sends a second request
- Load balancer sends it to the second node but the state of the aggregate in the second node is inconsistent because the event has not been sourced
I tried to implement a couple of solutions but none of them are satisfactory:
- Add an event listener to each node that it would check if the event is already in the store and if not, it would add it either directly or by materialising the aggregate and call apply(). This is a hack at the very best.
- Add an event listener that rebuilds the original command from the event and then it publishes to the local command bus. Worse idea than before as the command handling method of the aggregate could affect the outside world (e.g. send an e-mail).
- Create bespoke commands for state replication like ApplyEventCommand which sole purpose is to have the aggregate process event inside the command itself. Again poor solution as the command does not express a business intention and it’s just a work around.
Has anybody successfully scaled an axon application horizontally? If so, could you please provide some suggestions on how it could be done?