Restoring ES aggregates from AggregateSnapshot

Hi folks,

I’m implementing the snapshotting functionality and I got a little confused.
I defined a trigger definition to create snapshots and can see the snapshots stored in Axon Server (snapshot tab).

It was a surprise for me that I actually get a snapshot more often then I configured. The configured trigger is a count-based trigger with value of 5.

A second thing I realized, that the sourcing event handlers are still invoked and replay the entire event history.

My example is a slightly modified clone of the Axon Bank application. I created an account there and submitted commands adding an amount to the same aggregate (increasing the amount each time). Without snapshotting, every command handling loads the aggregate and sources all events… With the snapshotter - it does the same…

To check this, I just added log statements into my event sourcing handlers:

@Aggregate(snapshotTriggerDefinition = BankAccountAggregate.SNAPSHOT_TRIGGER)
public class BankAccountAggregate {


// more command handlers here

  @EventSourcingHandler
  void on(BankAccountCreatedEvent evt, MetaData metaData) {
    log.info("replaying event: {} with metadata {}", evt, metaData);
    this.accountId = evt.getAccountId();
    this.currentBalance = evt.getInitialBalance();
    this.maximalBalance = evt.getMaximalBalance();
  }

  @EventSourcingHandler
  void on(MoneyWithdrawnEvent evt, MetaData metaData) {
    log.info("replaying event: {} with metadata {}", evt, metaData);
    decreaseCurrentBalance(evt.getAmount());
  }

  @EventSourcingHandler
  void on(MoneyDepositedEvent evt, MetaData metaData) {
    log.info("replaying event: {} with metadata {}", evt, metaData);
    increaseCurrentBalance(evt.getAmount());
  }
}

My trigger definition is:

  @Bean(name = BankAccountAggregate.SNAPSHOT_TRIGGER)
  public SnapshotTriggerDefinition bankAccountAggregateSnapshotTriggerDefinition(
    Snapshotter snapshotter,
    @Value("${axon.aggregate.bank-account.snapshot-threshold:10}") int threshold) {
    return new EventCountSnapshotTriggerDefinition(snapshotter, threshold);
  }

If I got it right, this should use the default SpringAggregateSnapshotter which creates AggregateSnapshot events and the AggregateFactory should use those instead of replaying everything from event 1. Is my assumption correct?

2022-07-13 14:33:43.891  INFO 449006 --- [mandProcessor-0] f.bank.domain.BankAccountAggregate       : replaying event: {"accountId": "1", "initialBalance": 0, "maximalBalance": 1000} with metadata 'traceId'->'e1137688-d3fc-4dea-bbe4-3f9996f93ca0', 'correlationId'->'e1137688-d3fc-4dea-bbe4-3f9996f93ca0'
2022-07-13 14:33:43.892  INFO 449006 --- [mandProcessor-0] f.bank.domain.BankAccountAggregate       : replaying event: {"accountId": "1", "amount": 1} with metadata 'traceId'->'790c69de-1e2a-485f-90f8-85283f762e31', 'correlationId'->'790c69de-1e2a-485f-90f8-85283f762e31'
2022-07-13 14:33:43.892  INFO 449006 --- [mandProcessor-0] f.bank.domain.BankAccountAggregate       : replaying event: {"accountId": "1", "amount": 2} with metadata 'traceId'->'e759fdd3-567d-4460-9468-2b45a8ddae8e', 'correlationId'->'e759fdd3-567d-4460-9468-2b45a8ddae8e'
2022-07-13 14:33:43.893  INFO 449006 --- [mandProcessor-0] f.bank.domain.BankAccountAggregate       : replaying event: {"accountId": "1", "amount": 3} with metadata 'traceId'->'5de60f16-d2a6-4a0a-b744-0fe1bc53e24b', 'correlationId'->'5de60f16-d2a6-4a0a-b744-0fe1bc53e24b'
2022-07-13 14:33:43.894  INFO 449006 --- [mandProcessor-0] f.bank.domain.BankAccountAggregate       : replaying event: {"accountId": "1", "amount": 4} with metadata 'traceId'->'7270f8fa-3e15-4a26-85cd-0dffea423e0d', 'correlationId'->'7270f8fa-3e15-4a26-85cd-0dffea423e0d'
2022-07-13 14:33:43.894  INFO 449006 --- [mandProcessor-0] f.bank.domain.BankAccountAggregate       : replaying event: {"accountId": "1", "amount": 5} with metadata 'traceId'->'7836053a-efee-4447-93b0-955fcccec2e1', 'correlationId'->'7836053a-efee-4447-93b0-955fcccec2e1'
2022-07-13 14:33:43.894  INFO 449006 --- [mandProcessor-0] f.bank.domain.BankAccountAggregate       : replaying event: {"accountId": "1", "amount": 6} with metadata 'traceId'->'739a04c0-8864-4e70-aa21-824ff820fdc9', 'correlationId'->'739a04c0-8864-4e70-aa21-824ff820fdc9'
2022-07-13 14:33:43.895  INFO 449006 --- [mandProcessor-0] f.bank.domain.BankAccountAggregate       : replaying event: {"accountId": "1", "amount": 7} with metadata 'traceId'->'10166b10-3824-40ea-ada1-ea5d85143d11', 'correlationId'->'10166b10-3824-40ea-ada1-ea5d85143d11'
2022-07-13 14:33:43.895  INFO 449006 --- [mandProcessor-0] f.bank.domain.BankAccountAggregate       : replaying event: {"accountId": "1", "amount": 8} with metadata 'traceId'->'8d0cb5a8-c259-4077-9f2f-51e3e6b3430d', 'correlationId'->'8d0cb5a8-c259-4077-9f2f-51e3e6b3430d'
2022-07-13 14:33:43.896  INFO 449006 --- [mandProcessor-0] f.bank.domain.BankAccountAggregate       : replaying event: {"accountId": "1", "amount": 9} with metadata 'traceId'->'d8dab6d9-d57b-44de-b3b8-177178f8007e', 'correlationId'->'d8dab6d9-d57b-44de-b3b8-177178f8007e'
2022-07-13 14:33:43.896  INFO 449006 --- [mandProcessor-0] f.bank.domain.BankAccountAggregate       : replaying event: {"accountId": "1", "amount": 10} with metadata 'traceId'->'18ed2311-1744-43c4-a378-8195f93de95e', 'correlationId'->'18ed2311-1744-43c4-a378-8195f93de95e'
2022-07-13 14:33:43.897  INFO 449006 --- [mandProcessor-0] f.bank.domain.BankAccountAggregate       : replaying event: {"accountId": "1", "amount": 10} with metadata 'traceId'->'6f7fc352-4180-4061-b6b3-a9225fba76c5', 'correlationId'->'6f7fc352-4180-4061-b6b3-a9225fba76c5'
2022-07-13 14:33:43.897  INFO 449006 --- [mandProcessor-0] f.bank.domain.BankAccountAggregate       : replaying event: {"accountId": "1", "amount": 11} with metadata 'traceId'->'4a93a0fc-b574-4f7a-b592-49fff4e4ced9', 'correlationId'->'4a93a0fc-b574-4f7a-b592-49fff4e4ced9'
2022-07-13 14:33:43.897  INFO 449006 --- [mandProcessor-0] f.bank.domain.BankAccountAggregate       : replaying event: {"accountId": "1", "amount": 12} with metadata 'traceId'->'9261ffc6-bbc5-4f85-a088-f8cc58257754', 'correlationId'->'9261ffc6-bbc5-4f85-a088-f8cc58257754'
2022-07-13 14:33:51.354  INFO 449006 --- [mandProcessor-1] f.bank.domain.BankAccountAggregate       : replaying event: {"accountId": "1", "amount": 13} with metadata 'traceId'->'2ae03860-27fe-442a-a143-52f20bddde6e', 'correlationId'->'2ae03860-27fe-442a-a143-52f20bddde6e'

Here is the source code: https://github.com/holixon/holi-bank-fixture

What am I doing wrong?

1 Like

We debugged a little and I have an additional question.

Setting snapshotFilter on an Aggregate resulted in a fact that the filter is created but is never invoked.
We found a place in Configuration where the value of snapshotFilteris determined by reducing the AggregateConfiguration property.

And finally, in the AxonServerEventStore there is a check in readEventData method which checks the flag in order to tell the event channel to load data with snapshots or not…

A surprise is in the line AxonFramework/AxonServerEventStore.java at f496fed2155d58362597a1f0f7ac33906432af73 · AxonFramework/AxonFramework · GitHub
saying that if the filter is NOT set, then we load snapshots, otherwise, no snapshots are loaded.

If I’m understanding it correctly, this check should be inverted…

Could it be the reason for not loading snapshots?

Cheers,

Simon

Hi folks,

I did an additional test. I switched off the Axon Server connector and replaced it by a JPA Event store. Now the snapshotter is still working and writing events. Loading of aggregates loads the snapshot and then continues with remaining events (as expected).

To me it seems to be a bug in Axon Server connector. (I created a bug report in GiHub Snapshots are not considered during loading of an Aggregate using Axon-Server-Connector · Issue #2285 · AxonFramework/AxonFramework · GitHub )

Cheers,

Simon

Hi Simon,
I checked the code sample you provided, and indeed it is not using the snapshot with Axon Server if there is a snapshot filter defined and the snapshot serializer is the same as the event serializer.
I will add the information to your bug report to ensure it will be fixed in the next release.
Regards,
Marc

3 Likes