Akka.Persistence.PostgreSql
Akka.Persistence.PostgreSql copied to clipboard
Snapshots Deserialize to JObject and then ignored
Related to: #63 and #49
I am currently using Akka.Persistence.PostgreSql
version 1.4.17 and have seen issues recovering from snapshots using the JSON format. I am using PersistentFSM<TState, TData, TEvent>
which is offered a snapshot which is subsequently ignored because it has not been deserialized to the correct type.
The actor handles this by reading all events from the journal instead so no errors are thrown, indeed its only by chance that I spotted this behavior.
protected override bool ReceiveRecover(object message)
{
switch (message)
{
case TEvent domainEvent:
this.StartWith(this.StateName, this.ApplyEvent(domainEvent, this.StateData));
return true;
case PersistentFSM.StateChangeEvent stateChangeEvent:
this.StartWith(this.StatesMap[stateChangeEvent.StateIdentifier], this.StateData, stateChangeEvent.Timeout);
return true;
case SnapshotOffer snapshotOffer:
if (!(snapshotOffer.Snapshot is PersistentFSM.PersistentFSMSnapshot<TData> snapshot))
return false; // <~~ snapshotOffer.snapshot is Newtonsoft.Json.Linq.JObject but should be PersistentFSM.PersistentFSMSnapshot<TData>
this.StartWith(this.StatesMap[snapshot.StateIdentifier], snapshot.Data, snapshot.Timeout);
return true;
case RecoveryCompleted _:
this.Initialize();
this.OnRecoveryCompleted();
return true;
default:
return false;
}
}
Reading the snapshot store from the DB I can see that the manifest field is ""
as was mentioned to be the issue in #63.
Following through the code I can see the same method mentioned is at fault for not adding the manifest correctly.
protected override void SetManifestParameters(object snapshot, DbCommand command)
{
Type type = snapshot.GetType();
Serializer serializerForType = this.Serialization.FindSerializerForType(type, this.Configuration.DefaultSerializer);
string str = "";
if (serializerForType is SerializerWithStringManifest withStringManifest)
str = withStringManifest.Manifest(snapshot);
else if (!serializerForType.IncludeManifest)
str = type.TypeQualifiedName();
this.AddParameter(command, "@Manifest", DbType.String, (object) str); // <~~ str = ""
this.AddParameter(command, "@SerializerId", DbType.Int32, (object) serializerForType.Identifier);
}
I have also tried switching to BYTEA with a mind to use my own serialization but the lack of manifest again prevents me from doing so. Journal entries looks to have manifest set correctly, this only seems to effect snapshots.
My akka.conf for context:
akka {
loglevel=DEBUG
loggers=["Akka.Logger.Serilog.SerilogLogger, Akka.Logger.Serilog"]
persistence {
fsm {
snapshot-after = 3 # for testing purposes, normally 100
}
journal {
plugin = "akka.persistence.journal.postgresql"
postgresql {
class = "Akka.Persistence.PostgreSql.Journal.PostgreSqlJournal, Akka.Persistence.PostgreSql"
connection-string = "<dbConnectionString>"
schema-name = public
table-name = event_journal
auto-initialize = on
stored-as = BYTEA
}
}
snapshot-store {
plugin = "akka.persistence.snapshot-store.postgresql"
postgresql {
class = "Akka.Persistence.PostgreSql.Snapshot.PostgreSqlSnapshotStore, Akka.Persistence.PostgreSql"
connection-string = "<dbConnectionString>"
schema-name = public
table-name = snapshot_store
auto-initialize = on
stored-as = JSON
}
}
}
}
@cumpsd your comment on #63 may be exactly what I am referring to potentially?
Yes, I think #63 was closed too soon