【问题标题】:Is there any way to wait for actor to be completely stopped?有什么办法可以等待演员完全停止?
【发布时间】:2017-05-21 02:48:20
【问题描述】:

据我所知,Akka.Net 中的所有操作都是异步的,Context.Stop() 只是向参与者发送一个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() 创建新参与者。当终端断开连接时,我停止了演员。

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

【问题讨论】:

  • 您应该阅读以下内容:* 生命周期监控又名 DeathWatch * 确认关闭:GracefulStop
  • 我想到的一个命题也是FSM。之后,actor 收到 Disconnect 消息,您切换到新状态并更改行为。因此,Connect 消息不会被常规处理。您还可以定义当 Connect 消息未处理时 actor 应该做什么。

标签: c# akka akka.net


【解决方案1】:

我决定完成处理Terminated 消息。

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

类似这样的:

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 之后没有停止,但无论如何我不知道如何等待它的终止。

【讨论】:

    【解决方案2】:

    你可以使用

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

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

    更新

    但是,如果您以后想重新创建具有相同名称的演员,您应该在演员的主管中收听已终止的消息。

    【讨论】:

    • 据我了解here 的注释,它不会帮助我:警告 请记住,演员停止和其名称被注销是发生的独立事件彼此异步。因此,在 GracefulStop() 返回后,您可能会发现该名称仍在使用中。为了保证正确注销,仅重用您控制的主管内的名称,并且仅用于响应 Terminated 消息,即不适用于顶级参与者。
    • 哦,对不起。我误解了你原来的问题。是的,Grasfull top 不会向您保证,该演员姓名已被注销。在您的情况下,您应该在 actor 中收听 Terminated 消息,该消息使用终端名称来监督您的 actor。
    猜你喜欢
    • 1970-01-01
    • 2012-09-18
    • 1970-01-01
    • 1970-01-01
    • 2015-05-06
    • 2015-11-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多