0

We use EventSourcedBehavior from akka-persistence 2.6.15 for an CQRS/EventSourcing application, with akka-persistence-jdbc 4.0.0 for storing events and snapshots in PostgreSQL DB.

We have state classes that we serialize with snapshots. But sometimes those state classes change, which makes reading snapshot fail obviously. We manage it by deleting those changed snapshots:

      delete from snapshot sn 
      where sn.persistence_id::uuid in (select id from some_entity_table);       

But for entities with a lot of events, when sending a new command, it takes a lot of time to get to the latest snapshot, resulting in timeout.

Would it be possible to force a rebuild of snapshots at the startup of the application?

KaC
  • 613
  • 6
  • 14
  • According to your needs you could use a [EventAdapter](https://doc.akka.io/docs/akka/current/persistence.html#event-adapters), or a [SerializerWithStringManifest](https://doc.akka.io/docs/akka/current/serialization.html#serializer-with-string-manifest) or a combination of both. – Johny T Koshy Dec 10 '21 at 09:21
  • Thank you for the suggestion. We use both, but events are (de)serializing correctly, and we don't want to maintain different versions of snapshots. `SerializerWithStringManifest.fromBinary` can either return a state, or fail. We just want to scrap existing snapshots and rebuild them when needed. – KaC Dec 10 '21 at 13:32

1 Answers1

0

Arguably the "true" solution to this is to use a SerializerWithStringManifest which can deserialize the previous snapshot formats into the current format. If using reflection-driven serialization, this may be more difficult. It also won't migrate the existing snapshots.

One trick you can do is add an explicit ForceSnapshot command into your persistent actor's protocol. This is pretty easy in the Classic API, where you have more control over snapshotting, so I won't go over that. In the EventSourcedBehavior Typed API, however, this requires a bit more subtlety with adding a SnapshotForced event and changing the snapshotWhen function to return true if the event is a SnapshotForced.

Whether Classic or Typed, you can then have your application force every persistenceId to write a new snapshot by taking advantage of the currentPersistenceIds Persistence Query:

val readJournal =
  PersistenceQuery(system).readJournalFor[JdbcReadJournal](JdbcReadJournal.Identifier)

val everythingSnapshotted =
  readJournal.currentPersistenceIds()
    .mapAsync(parallelism) { id =>
      // use the ask pattern to send a `ForceSnapshot` command and wait for reply
      ???
    }
    .runWith(Sink.ignore)
Levi Ramsey
  • 18,884
  • 1
  • 16
  • 30