简体   繁体   English

在 Docker linux 容器中运行的 BackgroundService class 未正常关闭

[英]BackgroundService class running in Docker linux container does not shutdown gracefully

I've created a worker service that inherits from Microsoft.Extensions.Hosting.BackgroundService which I then deploy to a docker linux container on my windows machine through visual studio debugger.我创建了一个从 Microsoft.Extensions.Hosting.BackgroundService 继承的工作服务,然后我通过 Visual Studio 调试器机器将其部署到 docker linux 容器。 I put a breakpoint on code that happens when the cancellationtoken.IsCancellationRequested is true.我在cancellationtoken.IsCancellationRequested 为真时发生的代码上设置了一个断点。 I then issue a "docker stop --time=30" to the container, the breakpoint is never hit and after 30 seconds the debugger stops forcefully.然后我向容器发出“docker stop --time=30”,断点永远不会命中,30 秒后调试器强制停止。

I also tried overriding the StopAsync method and put a breakpoint in there and that also does not get called.我还尝试覆盖 StopAsync 方法并在其中放置一个断点,并且也不会被调用。 I am running .net core 3, latest version of docker desktop.我正在运行 .net 核心 3,最新版本的 docker 桌面。 I have confirmed that StartAsync gets called.我已经确认 StartAsync 被调用。

This is my program file.这是我的程序文件。

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


        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, config) =>
                {
                    var builder = new ConfigurationBuilder().SetBasePath(Directory.GetCurrentDirectory())
                        .AddEnvironmentVariables().Build();
                })
                .ConfigureServices((hostContext, services) => { services.AddHostedService<Worker>();    });

    }

If anyone has an idea of what I missed, or a working example for a non webserver service that respects the stop i'd be very grateful.如果有人知道我错过了什么,或者尊重停止的非网络服务器服务的工作示例,我将非常感激。

Adding what my worker looks like:添加我的工人的样子:

using System;
using System.Threading;
using System.Threading.Tasks;

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace MyWorker
{
    public class Worker : BackgroundService
    {    
        public Worker(ILogger<Worker> logger, IConfiguration configs)
        {

        }

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

        public override Task StartAsync(CancellationToken cancellationToken)
        { 
            return base.StartAsync(cancellationToken);
        }


        protected override async Task ExecuteAsync(CancellationToken cancellationToken)
        {
            try
            {
                await DoWork(cancellationToken); //While loop that checks token in here
            }

            catch (Exception ex)
            {

                throw;
            }
        }
    }
}

To listen to Ctrl+C, SIGINT and SIGTERM you need to add Console Lifetime support , either through UseConsoleLifetime() or RunConsoleAsync ,eg:要收听 Ctrl+C、SIGINT 和 SIGTERM,您需要通过UseConsoleLifetime()RunConsoleAsync添加控制台生命周期支持,例如:

public static async Task Main(string[] args)
{
    CreateHostBuilder(args).Build().RunConsoleAsync();
}

or或者

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

If shutting down takes longer than the timeout set in ShutdownTimeout , a warning is logged.如果关闭时间超过ShutdownTimeout中设置的超时时间,则会记录警告。

How it works这个怎么运作

Knowing how the Console lifetime works can help troubleshoot delays.了解控制台生命周期的工作原理有助于解决延迟问题。

If you check the source, RunConsoleAsync is nothing more than a call to UseConsoleLifeTime().Build().RunAsync();如果您检查源代码, RunConsoleAsync 只不过是对UseConsoleLifeTime().Build().RunAsync();的调用。

The internal ConsoleLifetime class adds event listeners for the Cancel and ProcessExit events:内部ConsoleLifetime class 为CancelProcessExit事件添加事件侦听器:

AppDomain.CurrentDomain.ProcessExit += OnProcessExit;
Console.CancelKeyPress += OnCancelKeyPress;

Ctrl+C will only forwart the Stop request to the host : Ctrl+C 只会将停止请求转发给主机

private void OnCancelKeyPress(object sender, ConsoleCancelEventArgs e)
{
    e.Cancel = true;
    ApplicationLifetime.StopApplication();
}

The ProcessExit handler on the other hand will emit a warning if shutting down takes longer than the timeout specified in HostOptions.ShutdownTimeout :另一方面,如果关闭时间超过HostOptions.ShutdownTimeout中指定的超时时间, ProcessExit处理程序将发出警告:

private void OnProcessExit(object sender, EventArgs e)
{
    ApplicationLifetime.StopApplication();
    if(!_shutdownBlock.WaitOne(HostOptions.ShutdownTimeout))
    {
        Logger.LogInformation("Waiting for the host to be disposed. Ensure all 'IHost' instances are wrapped in 'using' blocks.");
    }
    _shutdownBlock.WaitOne();
    // On Linux if the shutdown is triggered by SIGTERM then that's signaled with the 143 exit code.
    // Suppress that since we shut down gracefully. https://github.com/aspnet/AspNetCore/issues/6526
    System.Environment.ExitCode = 0;
}

Well after 4 days I finally figured it out, the problem is not with the code or the docker, the problem is with the Visual Studio debugger. 4天后我终于弄明白了,问题不在于代码或docker,问题在于Visual Studio调试器。 If you are running your code by pressing play in VS2019 it will not respect the SIGTERM.如果您通过在 VS2019 中按播放来运行代码,它将不遵守 SIGTERM。 If you run through the manual docker run command you will see your code respond to a DOCKER STOP command.如果您通过手动 docker 运行命令运行,您将看到您的代码响应 DOCKER 停止命令。

There might be a way to get it to work eventually but I haven't found it.最终可能有办法让它工作,但我还没有找到。

Encrease shutdown timeout work for me.为我增加关机超时工作。 Thank you Panagiotis for share MS Docs.感谢 Panagiotis 分享 MS Docs。

Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
    services.Configure<HostOptions>(option =>
    {
        option.ShutdownTimeout = System.TimeSpan.FromSeconds(20);
    });
});

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM