Akka.NET持久性如何处理重放包含IActorRef的消息?

时间:2017-05-27 21:09:13

标签: c# akka.net akka.net-persistence

如果我向Akka.NET actor发送一条消息,该消息是一个包含IActorRef的对象,然后保留该消息,写入日志表的JSON如下所示:

{"$id":"1","$type":"LearningAkka.Program+BindReference, LearningAkka","Reference":{"$id":"2","$type":"Akka.Actor.ActorRefBase+Surrogate, Akka","Path":"akka://LearningAkka/user/$b#1222898859"}}

如果我理解这一点,那只是对actor实例的引用;创建它所需的“道具”不会存储在此消息中。

奇怪的是,我在重新启动应用后看到了那里的对象。但是,正如预期的那样,它不是在重启之前构建的。这位演员是从哪里来的? Akka Persistence是否找到了一个“足够相似”并且用它代替的演员?

以下C#测试应用程序创建一个对象,并发送一条消息将其绑定到另外三个之一。处理actor系统后,将从持久性(SQL Server)重新创建该对象,并检查引用。

我的预期行为是以下任何一种(我不确定什么是最合适的):

  • 无法创建actor,因为其中一条消息包含无法解析的引用。
  • actor引用为null,因为无法解析。
  • 演员参考指向死信或类似信件。

控制台输出:

[WARNING][27/05/2017 21:02:27][Thread 0001][ActorSystem(LearningAkka)] NewtonSoftJsonSerializer has been detected as a default serializer. It will be obsoleted in Akka.NET starting from version 1.5 in the favor of Hyperion (for more info visit: http://getakka.net/docs/Serialization#how-to-setup-hyperion-as-default-serializer ). If you want to suppress this message set HOCON `akka.suppress-json-serializer-warning` config flag to on.
From the first run B

[WARNING][27/05/2017 21:02:28][Thread 0001][ActorSystem(LearningAkka)] NewtonSoftJsonSerializer has been detected as a default serializer. It will be obsoleted in Akka.NET starting from version 1.5 in the favor of Hyperion (for more info visit: http://getakka.net/docs/Serialization#how-to-setup-hyperion-as-default-serializer ). If you want to suppress this message set HOCON `akka.suppress-json-serializer-warning` config flag to on.
From the second run B

C#:

using Akka.Actor;
using Akka.Event;
using Akka.Persistence;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LearningAkka
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var actorSystem = ActorSystem.Create("LearningAkka"))
            {
                var referenceA = actorSystem.ActorOf(Props.Create(() => new TestReferencedActor("From the first run A")));
                var referenceB = actorSystem.ActorOf(Props.Create(() => new TestReferencedActor("From the first run B")));
                var referenceC = actorSystem.ActorOf(Props.Create(() => new TestReferencedActor("From the first run C")));
                var actor = actorSystem.ActorOf(Props.Create(() => new TestActor()));
                actor.Tell(new BindReference { Reference = referenceB });
                actor.Tell(new CheckReference());
                Console.ReadLine();
            }

            using (var actorSystem = ActorSystem.Create("LearningAkka"))
            {
                var referenceA = actorSystem.ActorOf(Props.Create(() => new TestReferencedActor("From the second run A")));
                var referenceB = actorSystem.ActorOf(Props.Create(() => new TestReferencedActor("From the second run B")));
                var referenceC = actorSystem.ActorOf(Props.Create(() => new TestReferencedActor("From the second run C")));
                var actor = actorSystem.ActorOf(Props.Create(() => new TestActor()));
                actor.Tell(new CheckReference());
                Console.ReadLine();
            }
        }

        public struct BindReference { public IActorRef Reference; }
        public struct CheckReference { }

        public sealed class TestActor : ReceivePersistentActor
        {
            public override string PersistenceId => "test hardcoded";

            private IActorRef StoredFromMessage;

            public TestActor()
            {
                Command<CheckReference>(m => StoredFromMessage.Tell(m));
                Command<BindReference>(m => Persist(m, m2 => StoredFromMessage = m2.Reference));
                Recover<BindReference>(m => StoredFromMessage = m.Reference);
            }
        }

        public sealed class TestReferencedActor : ReceiveActor
        {
            public TestReferencedActor(string ourLabel)
            {
                Receive<CheckReference>(m => Console.WriteLine(ourLabel));
            }
        }
    }
}

HOCON:

      akka {
        persistence {
          journal {
            plugin = "akka.persistence.journal.sql-server"
            sql-server {
              class = "Akka.Persistence.SqlServer.Journal.SqlServerJournal, Akka.Persistence.SqlServer"
              connection-string = "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=LearningAkka;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"
              schema-name = dbo
              table-name = Journal
              auto-initialize = on
            }
          }
          snapshot-store {
            plugin = "akka.persistence.snapshot-store.sql-server"
            sql-server {
              class = "Akka.Persistence.SqlServer.Snapshot.SqlServerSnapshotStore, Akka.Persistence.SqlServer"
              connection-string = "Data Source=(localdb)\\MSSQLLocalDB;Initial Catalog=LearningAkka;Integrated Security=True;Connect Timeout=30;Encrypt=False;TrustServerCertificate=True;ApplicationIntent=ReadWrite;MultiSubnetFailover=False"
              schema-name = dbo
              table-name = Snapshot
              auto-initialize = on
            }
          }
        }
      }

有人可以评论一下这里的行为吗?谢谢。

1 个答案:

答案 0 :(得分:0)

从序列化数据中可以看出 - 您的IActorRef指向此地址akka://LearningAkka/user/$b。通常为未命名的演员放置$b。因此,它将始终是您在actor系统根目录中创建的第二个未命名的actor(据我所知)。

所以你是对的 - 系统行为在这里是未定义的。