有没有办法等待演员完全停止?
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
之后没有停止,但无论如何我不知道如何等待它终止。
据我所知,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
之后没有停止,但无论如何我不知道如何等待它终止。