Akka.net динамическое добавление ребенка
Есть сконфигурированный ActorSystem
с акторами, организованными иерархически следующим образом:
/user
/processes
/process1
/process2
/process3
Для генерации этой схемы я использую следующий код C#:
// in entry point
IActorRef processesCoordinatorActorRef = ActorSystem.ActorOf(Props.Create<ProcessesCoordinatorActor>(), "processes");
// in ProcessesCoordinatorActor.cs:
IActorRef processOneActorRef = Context.ActorOf(Props.Create<ProccessActor>(), "process1");
IActorRef processTwoActorRef = Context.ActorOf(Props.Create<ProccessActor>(), "process2");
IActorRef processThreeActorRef = Context.ActorOf(Props.Create<ProccessActor>(), "process3");
Моя проблема в том, что я хочу добавить ребенка-актера к process1
, process2
или process3
из кодаточки входа (вне ProcessActor).
Но теперь мои руки связаны, потому что IActorRef
скрывает от меня некий актерский экземпляр.
Как мне ее решить?
1 ответ:
Дочерний актер должен быть создан в
Context
родительского актора. Если вы хотите, чтобы это произошло извне, просто отправьте сообщение родителю и попросите его создать дочернего актора (например,CreateChildActor
). Нет никакого способа создать актера в одном месте, а затем "усыновить" его как ребенка другого актера.Как правило (и не зная, что вы на самом деле пытаетесь сделать), мое предчувствие заключается в том, что создание актеров вниз по иерархии из вашего кода верхнего уровня / точки входа не является хорошее направление для вас, чтобы спуститься. Вы должны позволить родительским актерам в иерархии выполнять свою работу по созданию и надзору за детьми.
Если вам нужно было запустить этот процесс из точки входа, вы могли бы отправить свой
CreateChildActor
в любую точку иерархии с помощьюActorSelection
и/или разрешить его вIActorRef
.Вот пример кода, показывающий, как это можно сделать, и пусть подпроцесс уведомит координатора, как только он будет готов (также здесь в качестве скрипки):
using System; using System.Threading; using Akka.Actor; namespace ProcessActors { class Program { /// <summary> /// Top-level process coordinator actor. /// </summary> public class ProcessesCoordinatorActor : ReceiveActor { public ProcessesCoordinatorActor() { Receive<CreateChildActor>(createRequest => { Console.WriteLine("{0} creating child actor: {1}", Self.Path, createRequest.ChildName); var child = Context.ActorOf(createRequest.ChildProps, createRequest.ChildName); if (createRequest.ActorToNotify != null) createRequest.ActorToNotify.Tell(new ReadyForWork(child)); }); Receive<ReadyForWork>(ready => { Console.WriteLine("Coordinator sees worker ready: {0}", ready.Worker.Path); }); ReceiveAny(o => { Console.WriteLine("{0} received {1}", Self.Path, o); }); } } /// <summary> /// Actor for a given process. /// </summary> public class ProcessActor : ReceiveActor { public ProcessActor() { Receive<CreateChildActor>(createRequest => { Console.WriteLine("{0} creating child actor: {1}", Self.Path, createRequest.ChildName); var child = Context.ActorOf(createRequest.ChildProps, createRequest.ChildName); if (createRequest.ActorToNotify != null) createRequest.ActorToNotify.Tell(new ReadyForWork(child)); }); ReceiveAny(o => { Console.WriteLine("{0} received {1}", Self.Path, o); }); } } /// <summary> /// Sub-process. /// </summary> public class SubprocessActor : ReceiveActor { public SubprocessActor() { ReceiveAny(o => { Console.WriteLine("{0} received {1}", Self.Path, o); }); } } public static void Main(string[] args) { using (var system = ActorSystem.Create("MyActorSystem")) { Console.WriteLine("Starting up."); var coordinator = system.ActorOf(Props.Create(() => new ProcessesCoordinatorActor()), "processes"); var processProps = Props.Create(() => new ProcessActor()); // create process actors coordinator.Tell(new CreateNewProcess("process1", processProps)); coordinator.Tell(new CreateNewProcess("process2", processProps)); coordinator.Tell(new CreateNewProcess("process3", processProps)); var subprocessProps = Props.Create(() => new SubprocessActor()); // tiny sleep to let everything boot Thread.Sleep(TimeSpan.FromMilliseconds(50)); // get handle to an actor somewhere down in the hierarchy var process1 = system.ActorSelection("/user/processes/process1").ResolveOne(TimeSpan.FromSeconds(1)).Result; // create subprocess of process1 and notify the coordinator of new subprocess actor process1.Tell(new CreateNewSubprocess("subprocess1", subprocessProps, coordinator)); Console.ReadLine(); } } #region Messages /// <summary> /// Command to create ChildProps actor and notify another actor about it. /// </summary> public class CreateChildActor { public CreateChildActor(string childName, Props childProps, IActorRef actorToNotify) { ChildName = childName; ActorToNotify = actorToNotify; ChildProps = childProps; } public CreateChildActor(string childName, Props childProps) : this(childName, childProps, null) { } public Props ChildProps { get; private set; } public string ChildName { get; private set; } public IActorRef ActorToNotify { get; private set; } } public class CreateNewProcess : CreateChildActor { public CreateNewProcess(string childName, Props childProps, IActorRef actorToNotify) : base(childName, childProps, actorToNotify) { } public CreateNewProcess(string childName, Props childProps) : this(childName, childProps, null) { } } public class CreateNewSubprocess : CreateChildActor { public CreateNewSubprocess(string childName, Props childProps, IActorRef actorToNotify) : base(childName, childProps, actorToNotify) { } public CreateNewSubprocess(string childName, Props childProps) : this(childName, childProps, null) { } } /// <summary> /// Report to another actor when ready. /// </summary> public class ReadyForWork { public ReadyForWork(IActorRef worker) { Worker = worker; } public IActorRef Worker { get; private set; } } #endregion } }