I am implementing an EventSourcing application that handles a large number of original and derived data points. In short, we have an PersistentActor
functioning as an Aggregate Root accepting commands:
UpdateValue(name, value, timestamp)
UpdateValue(name, value, timestamp)
UpdateValue(name, value, timestamp)
After these commands are verified, they produce events which are persisted and update the state:
ValueUpdated(name, value, timestamp)
ValueUpdated(name, value, timestamp)
ValueUpdated(name, value, timestamp)
In a PersistentView
we listen to these events and calculate derived values:
case v @ ValueUpdated("value_i_care_about", _, _) => calculate_derived_values(v)
case v @ ValueUpdated("another_value_i_care_about", _, _) => calculate_derived_values(v)
But this recalculation itself is a new value on which other views could depend, so that means that we have to send a new command back to the aggregate root to process the new value, which can produce events that can be picked up by this or other views.
Is it acceptable for a view to produce events or commands? I would think a view's responsibility is to update a state based on events, not produce events or commands. Also, the order in which events arrive can influence the new events being broadcast during replay.
Is it necessary to produce commands instead of events? Since the command was updating the initial value, you could argue that producing all the derived values are simply events that are the result of the command being processed, although they are generated in a distributed fashion and not directly by the aggregate root.
I've been looking at Akka's Reactive Streams that could be used to string these actors together, and also looked at the idea of Sagas as presented here: http://blog.jonathanoliver.com/cqrs-sagas-with-event-sourcing-part-i-of-ii/. In that post Jonathan mentions:
Sagas listen to events and dispatch commands while aggregates receive commands and publish events.
That seems like a sensible approach as well, to implement all these actors as FSMs: wait 5 seconds for related events, recalculate everything, dispatch command, wait 5 seconds for events, etc.
To make things a little bit more interesting, the streams of values can be out of order and incomplete, but should produce derived values at points in time. So if I receive values A & B:
- A1, B1, B2, A2, B3, A4, B4
it should produce derived values D:
- D1 (A1 * B1), D2 (B2 * A2), D3 (B3 * A2, there is no A3), D4 (A4 * B4)
This means I have to keep track of order, and sometimes reissue a derived value if a missing value comes in.
Thanks!