Implementation of replay view model

I have a simple project that requires alot of reads and not many writes (once a day there are thousands of new registers per day, has hundreds of reads per minute, very little update to objects already present, a few per week), but I needed the application to be mindfull of past states of the model that the user is reading.

So if by any means a user makes a change to the object today, he must still be able to query the state of that object yesterday (necessary for analytical data to be precise).

This weekend I read on Event sourcing and created my own implementation with commands and events that were able to build from ground up the object and it mantained in the JPA repo the object and the events, and had a simple method for “reading old versions” which I simply give the timestamp or version number, and it would reload the events or an early snapshot and applies them until the model is in its desired version, then it would return it to the user, but the system is not very robust (I’ve made it in an afternoon) so I decided to try something more robust and with a proper community, already production proven. Axon got my attention instantly, but I cant find a way to do the replay for the view model with events (I already have a view model implemented by a projector, which updates the view model directly in the JPA repository), nor how could I rerurn a view model from scratch and rebuild my database (imagine someone commited a code which removed a very important EventHandler method from the projector and it simply made all view models of the last 12 hours unusables, how to I rerun it to rebuild my view models in the JPA to a usable state?)

To make queries that reflect states of the view model in time I am trying to implement it in a way in the view model, but this makes me think why should I even bother with event sourcing to build the state if I’m not going to use the power of the event sourcing to be able to do that?

Some of the things I’ve already tried are

  • use the EventStore.load(“entity”, expectedVersion), without any result.
  • Load an aggregate from a snapshot (I could not figure out how to do that)

I read in this forum that it should be possible to do something and receive an DomainEventStream to build a new aggregate, but I’d much prefer to separate the domain model from my view model, and since the view model is built using event handlers, how would I be able to rehidrate a new aggregate until the desired version of the domain model and then map it to my view model without breaking the sepparation betwen both (aka.: without placing query handlers inside the domain model?

One possible solution I see is to query directly the events and deserialize them, and use then in even another view model, this one being specificallt to rebuild objects given a list of ordered events, but again, since the framework already does something like this with the aggregate it makes me think that I’d be reinventing the well, and probably not even a round one!

If you have indication of example projects I could read would be great, I am very excited with Axon, and pondering if I should stick with 3.4 or go to 4.0 anyway, and I’ll use it in production, but I’d like to understand how to be able to do those things would help alot.

Hi Lucas,

Event Sourcing from Axon perspective, as you’ve noted, revolves around the Aggregates/Command Model, as this is the hardest bit to get right in regards to event sourcing.

The idea behind this is that an Aggregate is based on a specific stream of events for a given Aggregate system.
A View/Query Model is however interested in the entire event stream to be able to create a worthwhile model to answer your requests for data.

Between the lines of your request I believe the gist is that you’re looking to create a Query Model which you can query at a certain point in time.
There is no immediate infrastructure tool in Axon which provides this, but it is certainly doable by reusing existing components in place.
Due to the aforementioned specifics upon retrieving a stream of events which differs for Aggregates and Query Models, the EventStore provides two way to read events.

  1. EventStore#readEvents(String) / EventStore#readEvents(String, long)

  2. EventStore#openStream(TrackingToken)

Option one is used to retrieve a stream of evens to “Event Source an Aggregate” instance.
Option two is what Axon uses to feed events to Tracking Event Processors (Tracking Event Processors are what allows users to replay events to recreate Query Models).
The last option allows you to retrieve a stream at a certain point in time, since you can adjust the Tracking Token to be positioned at a specific point on the stream.

What you could do to create the desired Query Model, is to create a service which:

  1. Can handle queries for the desired model based on Id and timestamp/version number.
  2. Has event handlers to update the current Query Model.
  3. If an older version of the model is queried you can retrieve the Event Stream and replay it manually against your Event Handlers. You should stop the replay after you’ve hit Event at point-in-time X (depending on the query you’ve made). To be able to manually publish events to your Event Handlers outside of Axon specific components, you should create an AnnotationEventHandlerAdapter by providing it your Event Handling class, after which you call the canHandle() and in case that returns true the handle() functions respectively.

4 (Optional). Has logic in place to create a snapshot at certain critical moments in time to speed up this process.

That’s my two cents, hope this helps you out Lucas.

Cheers,
Steven

Thanks steve,

1. Can handle queries for the desired model based on Id and timestamp/version number.
This is probably where Im headed, simplicity over complexity, and allows for querying in the database also, which is a plus.

3. If an older version of the model is queried you can retrieve the Event Stream …
Easier to build from scratch, since I have almost no knowledge on the axon framework to do those implementations by hand.

Just one other point Id like to ask, I tried to pass a “custom config” XStream serializer, but it complained of the safety features not being set. I could not find inside the axon code how/where is the Xstream declared. All I needed was to set the annotationAutoDetect as enabled so I can annotate my events with more meaningfull names (and which allows for refactoring, because Im not rewriting my database just because I fixed a typo in the package), is there a way to inject this option in the already present Xstream serializer?

other than that, I read in the docs that it is suggested that you have a single aggregate to deal with complex objects, well, one of those objects I have is a nested object (a composite with object with a list of child composites, and each composite has a ref to its parent), I did the implementation which each composite is its own aggregate, and it works perfectly and I already did some stress test with 10k commands updates to test the time it take without snapshots (quite good, took just 700ms to rebuild the state without snapshots for every new command after 10k), but would it be better to build the composite as a single “complex” entity instead of many loosely connected aggregates? Right now they reference each other only by ID, and when I add a child I need to use a saga to publish the commands in the correct order and certify they actually work, but the coupling is very loose.Would it be better to allow the aggregate to be a complex nested object with lots of references instead of small simple ones?

Hi Lucas,

No worries Lucas, I am happy to be of service here! :slight_smile:

In notice two follow up question from your reply, so let’s get to that:

  1. This security complaint of XStream was introduced in the latest version upgrade of the ‘com.thoughtworks.xstream’ library.

Sadly, we cannot easily enforce this setting ourselves, hence why it is still in place.

You can configure the XStream instance used by your XStreamSerializer yourself though.

Assuming you’re on Axon 4, you can simply use the Builder paradigm to instantiate an XStreamSerializer builder.

This builder provides you with the XStreamSerializer.Builder#xStream(XStream) function.

In your configuration you could thus adjust the security settings on the XStream instance and then provide it to the XStreamSerializer you’d like to use.

I assume this should do the trick, if not, please provide a follow up to this response.

  1. You state that the reference guide suggests that you create one composite complex aggregate instead of several.

This is definitely not intended. Would you mind pointing out where you’ve retrieved this information in the guide?

I’ll ensure we adjust it accordingly so that the gist of it conveys what we’d actually want to convey.

A part from that though, the situation you sketch, thus pulling apart your Command Model into separate Aggregate Roots, is completely fine.

What the documentation should portray is that an Aggregate might consist out of several entities in your system.

Whether you model those as actual entities under one Aggregate Root or as several Aggregates depends on numerous domain and design specific considerations.
Thus, how fine grained you go in regards to creating loosely coupled Aggregates, is up to you.
Typically a domain expert should be able to clarify which bits belong to one another. From there on, trying to deduce how often specific entities might be required to handle commands could be a good starting point.

That’s my two cents, hope this helps you out!

Cheers,
Steven