Akka.NET 集群节点正常关机
Akka.NET cluster node graceful shutdown
背景
我有一个 Akka.NET 集群,其中包含一个 Lighthouse 种子节点和两个其他节点 运行 actor 系统。当我尝试在我的一个集群节点上正常关闭时,我想看到至少有一个其他节点收到一条关于节点离开的消息,并且所有集群节点最终都排除了节点列表中的离开节点。
一旦处理完毕,我希望我应该能够关闭该节点,而不会让其他两个节点因为无法连接到关闭的节点而发疯。
我试过的
我现在拥有的是一个包含在 TopShelf 应用程序中的控制台应用程序:
class ActorService : ServiceControl
{
private ActorSystem _actorSystem;
public bool Start(HostControl hostControl)
{
_actorSystem = ActorSystem.Create("myActorSystem");
var cluster = Cluster.Get(_actorSystem);
cluster.RegisterOnMemberRemoved(_Terminate);
return true;
}
public bool Stop(HostControl hostControl)
{
var cluster = Cluster.Get(_actorSystem);
cluster.Leave(cluster.SelfAddress);
return true;
}
private void _Terminate()
{
_actorSystem.Terminate();
}
}
这是我的主要内容:
class Program
{
static int Main(string[] args)
{
return (int) HostFactory.Run(x =>
{
x.UseAssemblyInfoForServiceInfo();
x.RunAsLocalSystem();
x.StartAutomatically();
x.Service<ActorService>();
x.EnableServiceRecovery(r => r.RestartService(1));
});
}
}
当单步执行停止函数时,我看不到任何关于该节点离开其他节点的消息。但是,当函数 returns 时,其他节点开始喷出异常。
Akka.NET Gitter 频道中的一位用户说:
I have observed the same thing even without TopShelf I must say, with a pure
ASP.NET Core project after the webhost terminated.
问题
我可以添加什么来让其他节点收到关于该节点离开的消息?
我认为问题在于 Stop()
方法在离开完成之前完成。您应该等待 MemberRemoved 事件。
此 Stop()
方法将等到 MemberRemoved 回调被调用并发出信号表明它甚至已经终止了 actor 系统。
class Worker
{
private static readonly ManualResetEvent asTerminatedEvent = new ManualResetEvent(false);
private ActorSystem actorSystem;
public void Start()
{
this.actorSystem = ActorSystem.Create("sample");
}
public void Stop()
{
var cluster = Akka.Cluster.Cluster.Get(actorSystem);
cluster.RegisterOnMemberRemoved(() => MemberRemoved(actorSystem));
cluster.Leave(cluster.SelfAddress);
asTerminatedEvent.WaitOne();
//log.Info("Actor system terminated, exiting");
}
private async void MemberRemoved(ActorSystem actorSystem)
{
await actorSystem.Terminate();
asTerminatedEvent.Set();
}
}
注意:我检查了三种类型的应用程序如何毫无问题地离开集群。我在 GitHub 上托管了它。离开时仍然有一些异常和一些死信,但其他节点不再继续尝试重新连接到退出的节点。
我想 post 在此线程上进行更新,因为我们已经向 Akka.NET 添加了一个新功能,因为这个答案最初被接受:CoordinatedShutdown
它做了@ZoolWay 的答案在幕后所做的事情等等,但要使用它,您只需执行以下操作:
class Worker
{
private ActorSystem actorSystem;
public void Start()
{
this.actorSystem = ActorSystem.Create("sample");
}
public void Stop()
{
Task<Done> shutdownTask = CoordinatedShutdown.Get(actorSystem).Run(CoordinatedShutdown.ClrExitReason.Instance);
shutdownTask.Wait();
}
}
这更简单,可以处理更复杂的清理方案,例如在终止集群本身之前关闭 Akka.Cluster.Sharding。我相信这是自 Akka.NET 1.3.2 以来推荐的处理方式。
背景
我有一个 Akka.NET 集群,其中包含一个 Lighthouse 种子节点和两个其他节点 运行 actor 系统。当我尝试在我的一个集群节点上正常关闭时,我想看到至少有一个其他节点收到一条关于节点离开的消息,并且所有集群节点最终都排除了节点列表中的离开节点。
一旦处理完毕,我希望我应该能够关闭该节点,而不会让其他两个节点因为无法连接到关闭的节点而发疯。
我试过的
我现在拥有的是一个包含在 TopShelf 应用程序中的控制台应用程序:
class ActorService : ServiceControl
{
private ActorSystem _actorSystem;
public bool Start(HostControl hostControl)
{
_actorSystem = ActorSystem.Create("myActorSystem");
var cluster = Cluster.Get(_actorSystem);
cluster.RegisterOnMemberRemoved(_Terminate);
return true;
}
public bool Stop(HostControl hostControl)
{
var cluster = Cluster.Get(_actorSystem);
cluster.Leave(cluster.SelfAddress);
return true;
}
private void _Terminate()
{
_actorSystem.Terminate();
}
}
这是我的主要内容:
class Program
{
static int Main(string[] args)
{
return (int) HostFactory.Run(x =>
{
x.UseAssemblyInfoForServiceInfo();
x.RunAsLocalSystem();
x.StartAutomatically();
x.Service<ActorService>();
x.EnableServiceRecovery(r => r.RestartService(1));
});
}
}
当单步执行停止函数时,我看不到任何关于该节点离开其他节点的消息。但是,当函数 returns 时,其他节点开始喷出异常。
Akka.NET Gitter 频道中的一位用户说:
I have observed the same thing even without TopShelf I must say, with a pure ASP.NET Core project after the webhost terminated.
问题
我可以添加什么来让其他节点收到关于该节点离开的消息?
我认为问题在于 Stop()
方法在离开完成之前完成。您应该等待 MemberRemoved 事件。
此 Stop()
方法将等到 MemberRemoved 回调被调用并发出信号表明它甚至已经终止了 actor 系统。
class Worker
{
private static readonly ManualResetEvent asTerminatedEvent = new ManualResetEvent(false);
private ActorSystem actorSystem;
public void Start()
{
this.actorSystem = ActorSystem.Create("sample");
}
public void Stop()
{
var cluster = Akka.Cluster.Cluster.Get(actorSystem);
cluster.RegisterOnMemberRemoved(() => MemberRemoved(actorSystem));
cluster.Leave(cluster.SelfAddress);
asTerminatedEvent.WaitOne();
//log.Info("Actor system terminated, exiting");
}
private async void MemberRemoved(ActorSystem actorSystem)
{
await actorSystem.Terminate();
asTerminatedEvent.Set();
}
}
注意:我检查了三种类型的应用程序如何毫无问题地离开集群。我在 GitHub 上托管了它。离开时仍然有一些异常和一些死信,但其他节点不再继续尝试重新连接到退出的节点。
我想 post 在此线程上进行更新,因为我们已经向 Akka.NET 添加了一个新功能,因为这个答案最初被接受:CoordinatedShutdown
它做了@ZoolWay 的答案在幕后所做的事情等等,但要使用它,您只需执行以下操作:
class Worker
{
private ActorSystem actorSystem;
public void Start()
{
this.actorSystem = ActorSystem.Create("sample");
}
public void Stop()
{
Task<Done> shutdownTask = CoordinatedShutdown.Get(actorSystem).Run(CoordinatedShutdown.ClrExitReason.Instance);
shutdownTask.Wait();
}
}
这更简单,可以处理更复杂的清理方案,例如在终止集群本身之前关闭 Akka.Cluster.Sharding。我相信这是自 Akka.NET 1.3.2 以来推荐的处理方式。