Akka.NET 群集节点正常关闭

本文关键字:常关闭 节点 群集 NET Akka | 更新日期: 2023-09-27 17:56:35

Background

我有一个 Akka.NET 集群,其中包含一个灯塔种子节点和另外两个运行参与者系统的节点。当我尝试对其中一个群集节点执行正常关闭时,我希望看到至少一个其他节点收到有关节点离开的消息,并且所有群集节点最终都会排除节点列表中的离开节点。

一旦解决了这个问题,我希望我应该能够关闭节点,而不会让其他两个节点因无法连接到关闭的节点而发疯。

我尝试过什么

我现在拥有的是一个包装在 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));
        });
    }
}

单步执行 Stop 函数时,我看不到任何关于节点离开其他节点的消息。但是,当函数返回时,其他节点开始喷出异常。

Akka.NET Gitter频道的一位用户说:

我必须说,即使没有TopShelf 我也能观察到同样的事情,用纯粹的ASP.NET 虚拟主机终止后的核心项目。

问题

我可以添加什么才能让其他节点收到有关节点离开的消息?

Akka.NET 群集节点正常关闭

我认为

问题是Stop()方法在离开完成之前完成。您应该等待成员删除事件。

Stop()方法将等待,直到调用了 MemberRemove 回调,并发出信号,表明它甚至已终止执行组件系统。

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上托管了它。离开时仍然存在一些异常和一些死信,但其他节点不再不断尝试重新连接到退出的节点。

我想在这里发布有关此线程的更新,因为自从最初接受此答案以来,我们已经向 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。我相信,这是自 1.3.2 Akka.NET 以来推荐的做事方式。