如果我發送一個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
}
}
}
}
可能有人請在這裏的行爲有何評論?謝謝。
如果在重放事件時無法獲得演員參考,則「IActorRef」將指向死信。您可能會看到,如果您將akka.loglevel增加爲DEBUG,那麼通過該引用發送的消息將落在那裏。 – Horusiath
這正是我所期望的,但不是我所看到的;如上所述,IActorRef似乎指向創建新演員系統以來創建的不相關演員。如果我堅持引用在第一個actor系統中創建的第二個actor,那麼在恢復時,我會獲得對第二個actor系統中創建的第二個actor的引用,這個actor在實例化順序上是確定性的。 – jameswilddev