Automatic Persistence of Command State [Axon Framework]
Asked Answered
D

1

2

I'm looking into the Axon framework and I'm having a hard time with the automatic persistence of the command state.

I've looked at the documentation regarding the command model repository and from my understanding the state of the command model for the standard repository should be auto-persisted provided I have the correct dependencies. This sentiment is also present in another blog/tutorial I've looked at (you might need to scroll down a bit to the Repository section).

The problem is that although I've added the axon-mongo dependency, the command state is not being persisted automatically. I've tried to configure the relevant Repository beans as per the docs but It doesn't seem to have worked either. I'm not even sure whether this is required given that (from my understanding of the docs) you would do this mainly if you want to query the command state.

While I understand that I can create my own repository and save the entities myself (similar to this tutorial), I'd rather not given seems to provide this out of the box.

Am I missing something here?

NOTE: My Mongo setup seems to be correct since I've managed to persist my events in MongoDB as per the documentation.

UPDATE

As per Steven's comment (and subsequent comments), I decided to try and implement a state-stored aggregate however I found an issue with the (de)serialization of the aggregate. I've sent my Aggregate to Steven and he has confirmed that it is simple enough that it should be (de)serialized by XStream. I have also tried to serialize my aggregate using a standalone instance of XStream and it worked, which led me to believe that this is more of an Axon issue than an XStream issue. I also tried to use the Jackson and java (de)serializers (since they are the other options provided by Axon) and I found similar problems. I have concluded that this is an Axon bug and i have stopped trying to solve the issue.

Doctrinaire answered 20/6, 2019 at 7:6 Comment(1)
If you're using event sourcing, you shouldn't think of the 'aggregate state' as a file in the database. The state is in the event store, in the form of all events stored for that aggregate. For performance reasons, a 'snapshot' of the aggregate state is stored every so many (configurable) events, but that will not be the current state most of the time. The command model repository will read the event store. It's usually good practice to put data you want to read in the query model.Disarray
A
2

From your question it is not immediately clear if you are aware of the possible Command Model storage mechanisms you can choose from. So firstly, like @Mzzl points out in his comment, you can view the Command Model state from two angles:

  1. Event Sourced
  2. State-stored

By default, Axon Framework will set up your Aggregate with an EventSourcingRepository behind it. This means, that if an Aggregate (e.g. your Command Model) is required to handle a new Command, that the Aggregate will be loaded by retrieving a stream of all the events that it is has published. Second, it will call all the @EventSourcingHandler annotated methods on your Aggregate implementation to recreate the state of the Command Model. Lastly, once all the Events which are part of the Aggregate's Event Stream have been handled, the command will be provided to the @CommandHandler annotated method.

The state-stored approach is obviously a little different, as this means the entirety of your Aggregate will be stored in a repository.

Note though, that the State-Stored approach is only supported through the GenericJpaRepository class. Thus, storing the Aggregate in it's entirety in a MongoDB is not an option. If you are looking for an Event Sourcing approach for your Aggregate, the events can be sourced from any EventStore implementation covered by the framework. That thus means you can choose JPA, JDBC, MongoDb and Axon Server as the means to storing your events and retrieving a stream of events to recreate your Command Model.

Configuration wise, there are a couple of approaches to this. If you are using the Configuration API provided by Axon directly, you can use:

  1. AggregateConfigurer#defaultConfiguration(Class<A>) for an Event Sourced approach
  2. AggregateConfigurer#jpaMappedConfiguration(Class<A>) for a State-Stored approach

If you are in a Spring Boot environment with your application, it's a little simpler to switch between event sourced and state-stored. Simply having the @Entity annotation on your Aggregate implementation is sufficient for the framework to note you want to store the Aggregate as is.

Hope this sheds some light on the situation @The__Malteser!


Update

Based on the comments, it's clear that the XStreamSerializer which the framework uses by default to de-/serialize objects, is incapable of serializing your Aggregate instance in a State-Stored fashion.

Based on the exception you're receiving, being Cannot marshal the XStream instance in action, I did some searching/digging. I have a hunch that XStream is by default not capable to simply serialized non-static inner classes.

However, as we're not sure what the implementation is of your Aggregate, it's hard to deduce whether that's the problem at hand. Would you be able to share your implementation with us here so that we can better deduce whether an inner class is the problem?

Analogize answered 21/6, 2019 at 9:29 Comment(19)
Hi Steven, thank you for reply and apologies on the late reply. I knew about the event sourced and state sourced entities and your mention of @Entity actually pointed me to the right direction. I am following the example of state-stored-aggregates from the Axon Documentation but I keep getting No Command Handler Found. It seems to be solved if I annotate with @Aggregate (along with @Entity) but then I get Cannot marshal the XStream instance in action. Do you have any idea what I might be missing?Doctrinaire
Just to be clear, I understand that the problem is probably around the (de)serialization of my Events but I'm not exactly sure how to solve it since the documentation lacks some examples. If you have any examples (github project or otherwise) that would be preferred. Thanks.Doctrinaire
Thanks for the update on this @The__Malteser. Might be valuable to update your question with these points as well. Along side that, I would've assumed that a State-Stored Aggregate would be serializable through the XStreamSerializer, as that virtually serializes anything! Would you mind providing the stack trace containing the Cannot marshal the XStream instance in action exception you're getting? This might point to the problem at hand.Analogize
Hi @Steven. I have sent you my reply through chat since it is too long for a comment. I will update this thread once my issue is resolved.Doctrinaire
I've sent my Aggregate to Steven and he confirmed that my aggregate is simple enough that it should be easily (de)serialized by XStream. I have also tried the Java and Jackson serializes and none of them worked. I've also tried serializing my aggregate using just XStream (i.e. not Axon's XStream) and it was serialized correctly. This leads me to believe that this is an Axon issue.Doctrinaire
Darn, that's weird! Would you be able to provide a small sample project, share don GitHub, which shows this predicament? I'd love the understand why it does move through XStream, but doesn't through Axon's XStreamSerializer.Analogize
@Analogize is it possible for Axon to use both event sourcing for an aggregate (storing events in Axon Server) and also state sourcing for the aggregate (storing the latest version of the aggregate in a (separate) query db (postgres))?Multiangular
Axon can do both event publication to an EventStore instance and do State Storage for the Aggregate. However, that's not what's called Event Sourcing from Axon's perspective. Event Sourcing is really about sourcing the Command Model state from the events it has published. The State-Stored Aggregate approach replaces the idea of sourcing an Aggregate from it's events entirely.Analogize
@Analogize thanks for your answer. The way that the event sourcing builds the Aggregate state was not clear at all (for me) from the Axon 4 documentation - and I only learnt it when I got an IllegalStateException in my app. I understood that event-sourcing was the way we build the projection database from EventHandler methods with support for replay. The part I still don't get: if the queries are always made on a separate model, what is the point of the event sourced Aggregate?Glassco
More succinctly @Steven: Why bother building/restoring the Aggregate state from the event store if noone ever asks for its state because the state "asked for" (queried) is always in the query projections?Glassco
Fair questions @Rhubarb! By employing event sourcing, you will ensure events are used for all types of models. Differently put, both for business validation and state requests. Again, in other words, to support CQRS in a way that the data originates from a single source. Ensuring the data comes from a single source eliminates the possibilities for inconsistency. And if it's found, that warrants a reconstruction (e.g. sourcing the model from events) of the aggregate.Analogize
> The way that the event sourcing builds the Aggregate state was not clear at all (for me) from the Axon 4 documentation That means there's a job to do! Would you mind constructing an issue on the Reference Guide's GitHub so that this pointer isn't lost? Thanks in advance! github.com/AxonIQ/reference-guideAnalogize
Thanks @Analogize - I will do that. Also not clear (until I coded it and watched it over the weekend) is that state-stored entities also support full replay - so you can still fully event source projections.Glassco
Just one clarification though please. When you say "ensure events are used for all..." Are you alluding to the fact that while I should never update state in my CommandHandlers, but only in EventHandlers, an ES Aggregate will enforce that rule, thus ensuring I can't accidentally code state changes that would be missed in my projections or replays thereof?Glassco
@Analogize github.com/AxonIQ/reference-guide/issues/234Glassco
Spotted the issue, thanks, @Rhubarb! To go to your follow-up question, yes, Axon's test fixtures enforce that you don't make state changes in Command Handlers whenever you're Event Sourcing.Analogize
My main intent with the argument, though, is to point out that you'd use a single data source to base all models on. Sure, you'd project your events for querying (query-side) and potentially introduce snapshots for your aggregates (command-side), but you are always able to recreate any model at any moment in time if everything's based on the same set of events.Analogize
makes sense on first reading. Less on 2nd :) I think when you say any model you're pointing out that: not only can query models (projections) be rebuilt, but also aggregates. Correct? Makes sense, but then I remember: what are aggegates for, since we don't query them? The only reason to rebuild the aggregate from events is to handle the next command, which fires the next event... Or am I missing something? The any moment in time phrase makes me think I am. But querying - without rebuilding - at a specific point in time means querying the eventstore directly, right?Glassco
> what are aggegates for, since we don't query them? It's the aggregate that protects the consistency boundary you define within your application. It does so by defining a scope of state that is required to be consistent at all times. This allows you the certainty that any command your application handles is validated according to your business requirements. By using Event Sourcing, we thus ensure that both pillars of an application, the writes and the reads, are based on the same set of information, always.Analogize

© 2022 - 2024 — McMap. All rights reserved.