Orleans 2.0 官方文档 —— 5.5.12 集群和客户端 -> 配置指南 -> 关闭Orleans

本文档介绍了如何在应用程序退出之前,优雅地关闭Orleans Silo,首先是控制台应用程序,然后是Docker容器应用程序。

优雅地关闭 —— 控制台应用程序

下面的代码显示了如何优雅地关闭Orleans silo控制台应用程序,来响应用户按Ctrl + C(生成Console.CancelkeyPress事件)。

通常,当该事件处理程序返回时,应用程序将立即退出,导致灾难性的Orleans silo崩溃和内存状态丢失。但是在下面的示例代码中,我们设置了a.Cancel = true;以防止在Orleans silo完成正常关闭之前关闭应用程序。

using Microsoft.Extensions.Logging;
using Orleans.Configuration;
using Orleans.Hosting;
using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;

namespace MySiloHost {

    class Program {

        static readonly ManualResetEvent _siloStopped = new ManualResetEvent(false);

        static ISiloHost silo;
        static bool siloStopping = false;
        static readonly object syncLock = new object();

        static void Main(string[] args) {

            SetupApplicationShutdown();

            silo = CreateSilo();
            silo.StartAsync().Wait();

            /// Wait for the silo to completely shutdown before exiting. 
            _siloStopped.WaitOne();
        }

        static void SetupApplicationShutdown() {
            /// Capture the user pressing Ctrl+C
            Console.CancelKeyPress += (s, a) => {
                /// Prevent the application from crashing ungracefully.
                a.Cancel = true;
                /// Don't allow the following code to repeat if the user presses Ctrl+C repeatedly.
                lock (syncLock) {
                    if (!siloStopping) {
                        siloStopping = true;
                        Task.Run(StopSilo).Ignore();
                    }
                }
                /// Event handler execution exits immediately, leaving the silo shutdown running on a background thread,
                /// but the app doesn't crash because a.Cancel has been set = true
            };
        }

        static ISiloHost CreateSilo() {
            return new SiloHostBuilder()
                .Configure(options => options.ClusterId = "MyTestCluster")
                /// Prevent the silo from automatically stopping itself when the cancel key is pressed.
                .Configure(options => options.FastKillOnProcessExit = false)
                .UseDevelopmentClustering(options => options.PrimarySiloEndpoint = new IPEndPoint(IPAddress.Loopback, 11111))
                .ConfigureLogging(b => b.SetMinimumLevel(LogLevel.Debug).AddConsole())
                .Build();
        }

        static async Task StopSilo() {
            await silo.StopAsync();
            _siloStopped.Set();
        }
    }
}

当然,实现同一个目标还有许多其他方法。下面显示了一种方式,它在网上流行,但具有误导性,因为它不能正常起作用。不能正常起作用的原因是,它在尝试先退出的两个方法(Console.CancelKeyPress事件处理程序方法和static void Main(string[] args)方法)之间设置了竞争条件。当事件处理程序方法首先完成时(至少过了一半时间),应用程序将挂起而不是平稳地退出。

class Program {

    static readonly ManualResetEvent _siloStopped = new ManualResetEvent(false);

    static ISiloHost silo;
    static bool siloStopping = false;
    static readonly object syncLock = new object();

    static void Main(string[] args) {

        Console.CancelKeyPress += (s, a) => {
            Task.Run(StopSilo);
            /// Wait for the silo to completely shutdown before exiting. 
            _siloStopped.WaitOne();
            /// Now race to finish ... who will finish first?
            /// If I finish first, the application will hang! :(
        };

        silo = CreateSilo();
        silo.StartAsync().Wait();

        /// Wait for the silo to completely shutdown before exiting. 
        _siloStopped.WaitOne();
        /// Now race to finish ... who will finish first?
    }

    static async Task StopSilo() {
        await silo.StopAsync();
        _siloStopped.Set();
    }
}

优雅的关机 - Docker应用程序

待完成。

你可能感兴趣的:(Orleans)