akkadotnet / Akka.Quartz.Actor

Quartz scheduling actor
Apache License 2.0
55 stars 31 forks source link

Incorrect choice of serializer causes SerializationException #311

Closed object closed 1 year ago

object commented 1 year ago

Version Information Akka.NET 1.5.12 Akka.Quartz.Actor 1.5.1

Describe the bug If scheduled message has a type that uses non-default serializer, it fails to be deserialized when it's triggered.

To Reproduce Consider a message that implements maker interface IProtoBufSerializable (code in F#):

    [<ProtoContract; CLIMutable; NoComparison>]
    type Message =
        {
            [<ProtoMember(1)>]
            Description: string
        }
        interface IProtoBufSerializable

Here is serialization configuratIon:

serializers {
  hyperion = "Akka.Serialization.HyperionSerializer, Akka.Serialization.Hyperion"
  protobuf = "Sample.PersistentEvents+ProtobufSerializer, Sample"
}
serialization-bindings {
  "System.Object" = hyperion
  "Sample.PersistentEvents+IProtoBufSerializable, Sample" = protobuf
}
serialization-identifiers {
  "Akka.Serialization.HyperionSerializer, Akka.Serialization.Hyperion" = -5
  "Akka.Serialization.NewtonSoftJsonSerializer, Akka" = 1
  "Sample.PersistentEvents+ProtobufSerializer, Sample" = 127
}

When scheduling a message, Akka.Quartz actor uses non-standard Protobuf serializer:

    Serializer messageSerializer = system.Serialization.FindSerializerFor(message);
    var serializedMessage = messageSerializer.ToBinary(message);

But when message is deserialized, Akka.Quartz actor uses serializer for object:

var message = sys.Serialization.FindSerializerForType(typeof(object)).FromBinary(messageBytes, typeof(object)); Deserialization encounters unexpected binary stream and fails with System.Runtime.Serialization.SerializationException ("Failed to deserialize instance of type System.Object. Stream didn't returned sufficient bytes")

Expected behavior The same serializer should be used for both serialization and deserialization.

Actual behavior Different serializers are chosen for serialization and deserialization, causing deserialization failure with SerializationException

Environment Both Windows and Linux

object commented 1 year ago

An alternative for the solution I provided in the PR would be to use FindSerializerForType with the actual message type, not object. But this will require storing an additional type attribute (most likely assigned to the assembly qualified type of the scheduled message.