Asp.Net Core 3正常关闭会引发OperationCanceledException [英] Asp.Net Core 3 graceful shutdown throws OperationCanceledException

查看:42
本文介绍了Asp.Net Core 3正常关闭会引发OperationCanceledException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试正常终止ASP.Net Core 3.1服务(它将在Kubernetes中运行).当Kubernetes停止服务时,它将向应用程序发送一个SIGTERM事件,这时我希望正在进行的请求完成(可能需要几秒钟),然后再终止...我想我可以在托管服务中捕获它,因为在下面,因此不会立即停止.

I'm trying to gracefully terminate a ASP.Net Core 3.1 service (which will run in Kubernetes). When Kubernetes stops a service, it will send a SIGTERM event to the application, at which point I want in-flight requests to complete (which may take several seconds) before terminating... I think I can catch this in a hostedservice, as below, and hence not stop immediately.

以下方法有效,但超时时间为5秒或更长时间,我收到OperationCanceledException.谁能阐明我为什么会收到OperationCanceledException的原因,或者如何揭示出延迟SIGTERM事件以允许正常关闭的另一种方式?

The following works, but with a timeout of 5 seconds or longer, I receive an OperationCanceledException. Could anyone shed any light on why I get an OperationCanceledException or how shed any light on an alternative way to delay a SIGTERM event, to allow a graceful shutdown?

    public static int Main(string[] args)
    {
        var logger = NLogBuilder
            .ConfigureNLog("nlog.config")
            .GetCurrentClassLogger();
        try
        {
            CreateHostBuilder(args)
                .ConfigureServices((hostBuilderContext, services) => { services.AddHostedService<LifetimeEventsHostedService>(); })
                .Build()
                .Run();

            return 0;
        }
        catch (Exception e)
        {
            logger.Fatal(e, "Stopping due to exception");

            return -1;
        }
        finally
        {
            LogManager.Shutdown();
        }
    }

这是托管服务...

    internal class LifetimeEventsHostedService : IHostedService
    {
        private readonly Microsoft.Extensions.Logging.ILogger _logger;
        private readonly IHostApplicationLifetime _appLifetime;

        public LifetimeEventsHostedService(
            ILogger<LifetimeEventsHostedService> logger,
            IHostApplicationLifetime appLifetime)
        {
            _logger = logger;
            _appLifetime = appLifetime;
        }

        public Task StartAsync(CancellationToken cancellationToken)
        {
            _appLifetime.ApplicationStarted.Register(OnStarted);
            _appLifetime.ApplicationStopping.Register(OnStopping);
            _appLifetime.ApplicationStopped.Register(OnStopped);

            return Task.CompletedTask;
        }

        public Task StopAsync(CancellationToken cancellationToken)
        {
            return Task.CompletedTask;
        }

        private void OnStarted()
        {
            _logger.LogInformation("OnStarted has been called.");

            // Perform post-startup activities here
        }

        private void OnStopping()
        {
            _logger.LogInformation("OnStopping has been called.");
            // Perform on-stopping activities here


            // This works, but a timeout of 5 seconds or more subsequently causes an OperationCanceledException
            Thread.Sleep(5000);
        }

        private void OnStopped()
        {
            _logger.LogInformation("OnStopped has been called.");

            // Perform post-stopped activities here
        }
    }


推荐答案

我愿意使用ASP.Net Core 3.1进行正常关机的替代方法,就目前而言,我正在使用托管服务.

I'm open to alternative approaches to graceful shutdown with ASP.Net Core 3.1, as it stands, I'm using a hosted service.

在.Net Core应用程序中,我正在设置网络主机上的关机超时,但是,设置

Within the .Net Core app, I was setting ShutdownTimeout on the webhost, however, setting the ShutdownTimeout on the generic host, does allow me to gracefully wait a number of seconds (more than the default sigterm, which is 5 seconds) prior to shutdown. The hint from @PmanAce helped me work that out.

因此,以下代码允许我正常终止.一个警告,LifetimeEventsHostedService中的Thread.Sleep必须小于 option.ShutdownTimeout .

As such, the following codes allow me to gracefully terminate. One caveat, the Thread.Sleep in LifetimeEventsHostedService must be less than option.ShutdownTimeout.

public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureServices((hostBuilderContext, services) =>
            {
                services.AddHostedService<LifetimeEventsHostedService>();
                services.Configure<HostOptions>(option =>
                {
                    option.ShutdownTimeout = TimeSpan.FromSeconds(30);
                });
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseKestrel();
                webBuilder.UseStartup<Startup>();
            });
}

以下LifetimeEventsHostedService

The following LifetimeEventsHostedService

public class LifetimeEventsHostedService : IHostedService
{
    private readonly IHostApplicationLifetime _hostApplicationLifetime;

    public LifetimeEventsHostedService(IHostApplicationLifetime hostApplicationLifetime)
    {
        _hostApplicationLifetime = hostApplicationLifetime;
    }

    public Task StartAsync(CancellationToken cancellationToken)
    {
        _hostApplicationLifetime.ApplicationStarted.Register(OnStarted);
        _hostApplicationLifetime.ApplicationStopping.Register(OnStopping);
        _hostApplicationLifetime.ApplicationStopped.Register(OnStopped);

        return Task.CompletedTask;
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }

    private void OnStopped()
    {
        Console.WriteLine("OnStopped");
    }

    private void OnStopping()
    {
        Console.WriteLine("OnStopping");
        Console.WriteLine(DateTime.Now.ToLongTimeString());

        Thread.Sleep(15000);
        Console.WriteLine("Sleep finished");
        Console.WriteLine(DateTime.Now.ToLongTimeString());
    }

    private void OnStarted()
    {
        Console.WriteLine("OnStarted");
    }
}

这篇关于Asp.Net Core 3正常关闭会引发OperationCanceledException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆