2017-05-27 90 views
0

如果我发送一个Akka.NET演员的消息即含有IActorRef的对象,然后坚持这一信息,写入日志表中的JSON看起来是这样的:Akka.NET持久性如何处理重放包含IActorRef的消息?

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

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

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

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

我预期的行为是下列任何(我不知道什么是最适合的)的:

  • 演员不能被创建,因为它的信息之一包含一个不可避免的参考。
  • 参与者参考为空,因为它无法解析。
  • 演员参考指向死信或类似的。

控制台输出:

[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 
      } 
      } 
     } 
     } 

可能有人请在这里的行为有何评论?谢谢。

+0

如果在重放事件时无法获得演员参考,则“IActorRef”将指向死信。您可能会看到,如果您将akka.loglevel增加为DEBUG,那么通过该引用发送的消息将落在那里。 – Horusiath

+0

这正是我所期望的,但不是我所看到的;如上所述,IActorRef似乎指向创建新演员系统以来创建的不相关演员。如果我坚持引用在第一个actor系统中创建的第二个actor,那么在恢复时,我会获得对第二个actor系统中创建的第二个actor的引用,这个actor在实例化顺序上是确定性的。 – jameswilddev

回答

0

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

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