Search code examples
c#akka.netakka.net-persistence

Persistence failure when replaying events... System.NotSupportedException: Generic IDictionary are not yet supported


Can you please help? When saving one or two times works fine. Three or more and I am getting this:

    [INFO][11/28/2017 2:57:27 PM][Thread 0005][[akka://ECHO3DEV/user/api-master/PortfolioCoordinator/TK#425630680]] Portfolio Actor: TK completely recovered. Current Positions: ......
11/28/2017 9:57:27 AM portfolio- Actor started...
[ERROR][11/28/2017 2:57:27 PM][Thread 0005][[akka://ECHO3DEV/user/api-master/PortfolioCoordinator/TK/TK-IBM#1280277591]] **Persistence failure when replaying events for persistenceId [portfolio-TK-IBM]. **Last known sequence number [3]
Cause: System.NotSupportedException: Generic IDictionary<TKey,TValue> are not yet supported****
   at Hyperion.SerializerFactories.DictionarySerializerFactory.<>c__DisplayClass3_0.<BuildSerializer>b__0(Stream stream, DeserializerSession session)
   at Hyperion.ValueSerializers.ObjectSerializer.ReadValue(Stream stream, DeserializerSession session)
   at lambda_method(Closure , Stream , DeserializerSession )
   at Hyperion.ValueSerializers.ObjectSerializer.ReadValue(Stream stream, DeserializerSession session)
   at lambda_method(Closure , Stream , DeserializerSession )
   at Hyperion.ValueSerializers.ObjectSerializer.ReadValue(Stream stream, DeserializerSession session)
   at lambda_method(Closure , Stream , DeserializerSession )
   at Hyperion.ValueSerializers.ObjectSerializer.ReadValue(Stream stream, DeserializerSession session)
   at Hyperion.SerializerFactories.DefaultDictionarySerializerFactory.<>c__DisplayClass3_0.<BuildSerializer>b__0(Stream stream, DeserializerSession session)
   at Hyperion.ValueSerializers.ObjectSerializer.ReadValue(Stream stream, DeserializerSession session)
   at lambda_method(Closure , Stream , DeserializerSession )
   at Hyperion.ValueSerializers.ObjectSerializer.ReadValue(Stream stream, DeserializerSession session)
   at lambda_method(Closure , Stream , DeserializerSession )
   at Hyperion.ValueSerializers.ObjectSerializer.ReadValue(Stream stream, DeserializerSession session)
   at Hyperion.Serializer.Deserialize[T](Stream stream)
   at Akka.Serialization.HyperionSerializer.FromBinary(Byte[] bytes, Type type)
   at Akka.Persistence.Sql.Common.Journal.AbstractQueryExecutor.ReadEvent(DbDataReader reader)
   at Akka.Persistence.Sql.Common.Journal.AbstractQueryExecutor.<SelectByPersistenceIdAsync>d__44.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Akka.Persistence.Sql.Common.Journal.SqlJournal.<ReplayMessagesAsync>d__32.MoveNext()

How can I debug this?


Solution

  • This is not a problem with an Akka.Persistence itself. The bug itself lies within the Hyperion serializer, which you shouldn't use for persistence (only for remoting). After all, the data you're going to store is yours and it would be better if you keep a control over how it's going to be stored for yourself ;)

    I've described this and other common Akka.Persistence mistakes here.

    One of the reasons against using Hyperion for persistence, is that it's still in beta and its binary format is NOT set in stone. This means that after upgrading the serializer, you may no longer be able to read your events back.

    For that reason it's better to explicitly define a serializer with well-known schema for your events. You can decide to roll your own, or i.e. pick MsqPack or Microsoft Bond - they work on explicit schema definition, making it easier to work as time passes and event content changes.

    To define a custom serializer you need to mark your events with some type (i.e. empty interface), that you'll use to recognize which serializer apply to them. Then just simply define a serializer mapping in a HOCON configuration:

    akka.actor {  
      serializers.msgpack= "Akka.Serialization.MessagePack.MsgPackSerializer, Akka.Serialization.MessagePack"
      serialization-bindings {
        "MyNamespace.IDomainEvent, MyAssembly" = msgpack
      }
    }
    

    Here I'm using Akka.NET MsgPack serializer to custom interface IDomainEvent, which I'm going to recognize my events by. The fully qualified type names with assembly are needed for type recognition.