[axonframework] Digest for axonframework@googlegroups.com - 1 Message in 1 Topic

Have you seen Johnathan Oliver’s event sourcing saga implementation. No aggregates are involved here (except in the sense that they might be the source of the events being fed to the saga). The fact that the implementation of the saga might call methods on aggregates resulting in events being published is irrelevant to this discussion IMHO. One benefit that comes to mind is the general benefit of having that vcr-like capability that event sourcing in general brings to the table (rewind/pause/fast-forward/play), auditing, simpler saga storage requirements (especially if you’re already using event sourcing for aggregates).

Hi Jimit,

the problem is not so much in the technical aspect of things. It’s a conceptual thing. Jonathan’s implementation seems to assume that the output of a Saga is always a message. I am not entiry sure whether that is a good assumption, or a big restriction in of use cases.

Event sourcing mus use end results to rebuild current state. Is a case of a saga, the events are the source of change, not the result. A result is e.g. a command that has fired. It seems to me that, to apply ES to a saga, you’d need another set of events, local to the saga, that represent its changes.

I’m thinking this through. It still strikes me as a bit odd here. And if I’ve learnt one thing of applying DDD for several years now, it’s that ‘odd’ often means ‘out of place’ (or something I have to get used to, of course).

Cheers,

Allard

I think the reason he assumes saga output is always one or more messages is that he probably just uses sagas purely for coordination - they don’t directly mutate application state. Instead they issue commands or publish events and leave it to the handlers of those messages to effect the necessary state changes. I think that’s a good way to model sagas - it lets them concentrate on their main task which is to coordinate long-running , multi-step, transactions. Thus the only state the saga mutates directly it’s own state that it uses to track the state of the “transaction” (often done using a state machine - I believe he uses StateLess). I’m not sure if he’s on this list, but if so he’s welcome to stop me from putting words in his mouth. :wink:

In any case, I don’t think restricting sagas to only output messages rather than directly modifying state is too much of a restriction. It’s an application of SRP and, IMHO, a good idea.

Event Sourcing as a concept (IMHO) is simply using deltas to rebuild the current state of an object - it says nothing about how that state is rebuilt from the deltas; only that it is. The LMAX model is an example of a system that uses event sourcing to rebuild it’s state from “input events” rather than “output” events (as in the case of aggregates). Their “business logic processor”, as far as I can tell, is nothing but a humungous saga. In the case of event-sourced aggregates, the deltas just happen to be the output events - an implementation detail.

Hi Allard,

What about events that are not aggregate specific (means not raised by an aggregate)? For example timer events or an external event from outside the CQRS system?

Cheers,
Michael

I'm not sure how the source of the events makes a difference. The implementation I alluded to makes no distinction at all, instead just refers to them as messages so in theory could even be commands though I don't recommend sagas handling commands directly.

Sourcing the input of the Saga (i.e. the incoming events) is possible, but requires all output to be blocked during the “replay” of old events. It also expects the Saga to produce exactly the same state changes based on events, every time again. Although this sounds easy, I can see some areas where this could lead to problems. In the area of scheduling events for example. An then there is a problem when a Saga sends a command and takes action based on the result of a Command. Using input sourcing, you cannot reproduce that result without sending a command again.

In the case of non-domain events, like Michael points out, you won’t have an explicit log of the event unless you event source it. But those events don’t really represent a state change. The state change is typically done as a command dispatched by the saga as result of the event.

I just see too many little issues with “event” sourcing for Sagas currently. I’m not rejecting it, just finding a way to really make it work, without restricting implementation possibilities.

Cheers,

Allard

Isn't the purpose of his framework solely the event sourcing piece and
not CQRS?

Chad

I agree that event replay should not result in messages being sent or actions being taken etc. JOs implementation does handle that but his implementation is very opinionated and he’s able to cut a few corners because his commands are always async (which is not necessarily that restrictive). The result of a command is thus always an event delivered to the saga after the fact. Also with message output from the saga, the saga doesn’t send messages directly - instead it relies on the saga repository to dispatch messages on commit. So the way he tackles event replay is by feeding the input messages to the saga then clearing the undispatched messages and uncommitted events:


private static TSaga BuildSaga<TSaga>(IEventStream stream) where TSaga : class, ISaga, new()
		{
			var saga = new TSaga();
			foreach (var @event in stream.CommittedEvents.Select(x => x.Body))
				saga.Transition(@event);

			saga.ClearUncommittedEvents();
			saga.ClearUndispatchedMessages();

			return saga;
		}

Granted, this strategy isn't very suitable for request-reply command scenarios, but personally I don't see it as much of a restriction since I don't use request-reply commands :).
Another strategy is to have the saga state separate from the saga itself and use event sourcing on that. The resulting state is then used to construct the saga.

The EventStore project is solely for event sourcing. The saga implementation is from his CommonDomain project which is/was a spike of CQRS micro-framework.

This may take a little setup, so please bear with me, and I think that you will see how it is relevant.

Earlier, in another thread, I was very interested in everyone’s practical experience with replaying events. That conversation was soon followed by the suggestion of event sourcing sagas - which I do believe is what this conversation is an offshoot of.

I had a quick conversation with Rinat Abdullin about the series that he currently has on his blog, as it relates to replaying events (which you will find in Projections). Based on what he suggested, and also the conversation here regarding event sourcing sagas, I wonder is it worthwhile to entertain the idea of an event store that does not publish events.

If there was the possibility of storing events to an event store without publishing those events, then that would fit with Eugene’s suggestion for event sourcing sagas. It would also fit with the concept of replaying events from a separate event store (which is how I interpreted implementing a “replay” solution after Rinat’s post).

Would a separate event store implementation, one that does not publish events to the event bus, help?

Hi Carlus,

let me explain my view on Event Sourcing. But before I do that, in Axon, the Event Store is not reponsible for dispatching to the Event Bus. The repositories do that.

The way I see it, Event Sourcing is purely a storage concept. No more, no less. Instead of storing state, you store the deltas (with intent included). To rebuild the current state, you reply all relevant events.

If you look at Aggregates, they are feeded with Commands (either directly, or indirectly) and produce events. Meanwhile they keep state. If that aggregate is Event Sourced, you can use the events it generated to rebuild its state.

A Saga, however, is fed with Events, and produces Commands and other Events. That’s why Event Sourcing on the Saga level is not the same as ES on the aggregate level. Event Sourcing should be done with output results, not input. I know LMAX does input sourcing, and I believe they might get into trouble once they change the domain logic. How can you guarantee that the internal state is not semantically different after processing old commands?

If you ask me, replaying events from the Event Store is a completely different thing. Replaying events is used to rebuild state in certain components, such as the Query databases. These components should not produce side-effects. If they do (like it is the case with sagas, typically), you must be able to prevent these side effects from occurring.

Cheers,

Allard

Allard,

Thanks for the clarification distinction between the Repository and the Event Store. I had definitely lumped these two together.

I also agree with you that replaying events from the event store should not produce side effects, and understand the potential of issuing new commands / events if we started to event source sagas.

Perhaps this is not the best thread for the discussion, but with the ability to store events without publishing, (Event Store without the Repository), it could ease the ability to replay events in order to construct new view caches, or rebuild old ones. The other side effect is that if people find it beneficial to event source a Saga, they would not have to worry about the events being published to an event queue on save. Of course they would also have to be careful that those events that are used to rebuild state, would not generate any commands or publish any additional events on read. As you are saying that could be very dangerous.

Is the ability to use an Event Store without the Repository (publish on save) already supported?

Hi Carlus,

there is a method on EventStoreManagement (which JpaEventStore implements), which allows you to replay all events to your event handlers. Simply provide a “Visitor” that passes all (relevant) events to the handlers of choice.

So basic support is already available. Ideas have gone round to create an interface that event listeners can implement (or an annotation), which allows you to use JMX to trigger a “full rebuild” of an event handler. Axon will then also make sure new incoming events are “parked” until replaying is complete.

Cheers,

Allard