Как Akka.NET Persistence обрабатывает повторные сообщения, содержащие IActorRef?
Если я посылаю актеру Akka.NET сообщение, являющееся объектом, содержащим IActorRef, и затем сохраняю это сообщение, JSON, записанный в таблицу журнала, выглядит следующим образом:
{"$id":"1","$type":"LearningAkka.Program+BindReference, LearningAkka","Reference":{"$id":"2","$type":"Akka.Actor.ActorRefBase+Surrogate, Akka","Path":"akka://LearningAkka/user/$b#1222898859"}}
Если я правильно понимаю, это просто ссылка на экземпляр актера; "Реквизит", необходимый для его создания, не сохраняется в этом сообщении.
Странно, я вижу объект после перезапуска приложения. Однако, как и ожидалось, это не так, как построено до перезапуска. Откуда появился этот актер? Обнаружил ли Akka Persistance актер, который "достаточно похож", и использовал его вместо этого?
Следующее тестовое приложение C# создает объект и отправляет сообщение, связывающее его с одним из трех других. После удаления системы субъекта этот объект воссоздается из постоянства (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
}
}
}
}
Может ли кто-нибудь прокомментировать здесь поведение? Спасибо.
1 ответ
Как видно из данных сериализации - ваш IActorRef указывает на этот адрес akka://LearningAkka/user/$b
, куда $b
обычно размещается для неназванных актеров. Так что это всегда будет второй безымянный актер, которого вы создадите в корне системы акторов (насколько я знаю).
Так что вы правы - поведение системы здесь не определено.