有没有办法等待演员完全停止?

Is there any way to wait for actor to be completely stopped?

据我所知,Akka.Net 中的所有操作都是异步的,Context.Stop() 只是向 actor 发送一条 Stop 消息。这意味着,actor 在完全关闭之前会存活一段时间。

如果我在 Context.Stop() 之后立即调用 Context.Child() 并提供我刚刚停止的演员的名字,我将得到同一个演员。

这是示例代码

var actor = context.Child(actorName);

if (actor.Equals(ActorRefs.Nobody))
{
    actor = CreateNewActor();
}

Context.Stop(actor)
actor = context.Child(actorName);
// what do we get here, same actor or ActorRefs.Nobody ?

我的应用程序创建参与者来处理来自终端的事件。每次连接新终端时,我都会使用终端名称调用 Context.Child() 来创建新演员。当终端断开连接时,我会停止演员。

问题是有时我会在同一终端的断开连接后立即收到连接消息,结果我得到的演员将被停止。有什么方法可以检查 actor 是否收到了停止消息并将很快停止?

您可以使用

var shutdown = actor.GracefulStop(TimeSpan.FromSeconds(42));

它returns一个任务,其结果确认在 42 秒内关闭

更新

但是,以防万一,如果您想稍后使用相同的名称重新创建 actor,您应该在 actor 的主管中收听 Terminated 消息。

我决定结束对 Terminated 消息的处理。

收到 Disconnect 消息并停止 actor 后,我将其名称保存在 ActorsToBeStopped HashSet 中,在收到 Connect 消息创建新的 actor 之前,我检查它是否存在那里。如果是这样,我将此 Connect 消息保存在字典中,以演员名称为键, Connect 消息为值,并在收到相应演员的终止消息后对其进行处理。

像这样:

private readonly Dictionary<string, Connect> postponedConnectMessages = new Dictionary<string, Connect>();
private readonly HashSet<string> actorsToBeStopped = new HashSet<string>();

// ...

Receive<Disconnected>(t => 
{
    var actor = GetActorByName(t.Name);
    Context.Stop(actor);
    actorsToBeStopped.Add(actor.Path.Name);
});

Receive<Connected>(t =>
{
    var actor = GetActorByName(t.Name);

    if (actorsToBeStopped.Contains(actor.Path.Name))
    {
        postponedConnectMessages[actor.Path.Name] = t;
        return;
    }
    // work with actor
}

Receive<Terminated>(t =>
{
    var deadActorName = t.ActorRef.Path.Name;
    actorsToBeStopped.Remove(deadActorName);
    if (postponedConnectMessages.ContainsKey(deadActorName))
    {
        var connectMessage = postponedConnectMessages[deadActorName];
        postponedConnectMessages.Remove(deadActorName);
        var actor = GetActorByName(connectMessage.Name);
        // we sure we have new actor here
        // work with actor
    }
}

编辑

可悲的是我无法为它编写测试,因为 Akka.TestKit 不允许我创建具有相同名称的 TestActor,即使它已停止:

public void StopTest()
{ 
    var t = CreateTestActor("AAAA");
    Watch(t);
    Sys.Stop(t);
    ExpectTerminated(t, TimeSpan.FromSeconds(10));
    var t2 = CreateTestActor("AAAA"); // test fails here
}

或者,也许它在 ExpectTerminated 之后没有停止,但无论如何我不知道如何等待它终止。