2017-05-27 33 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(據我所知)。

所以你是對的 - 系統行爲在這裏沒有定義。