Akka.NET集群节点正常关闭

时间:2016-07-11 14:26:40

标签: c# akka.net akka.net-cluster

背景

我有一个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));
        });
    }
}

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

Akka.NET Gitter频道的用户说:

  

即使没有TopShelf,我也观察过同样的事情   webhost终止后的ASP.NET Core项目。

问题

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

2 个答案:

答案 0 :(得分:19)

我认为问题是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上托管了该内容。离开时仍有一些例外和一些死信,但其他节点不再继续尝试重新连接到退出的节点。

答案 1 :(得分:4)

自从我们最初接受此答案以来,我们已经在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起,这是推荐的处理方式。