使用通用主机IHostBuilder时如何从Docker检测到关机信号

8

我有以下默认的通用主机生成器:

public static IHostBuilder CreateDefaultBuilder(string[] args)
{
    var builder = Host.CreateDefaultBuilder(args);

    builder
        .ConfigureLogging((hostingContext, logging) =>
        {
            logging.ClearProviders();
            logging.AddConsole();
            if (hostingContext.HostingEnvironment.IsDevelopment() == true)
                logging.AddDebug();
        })
        .ConfigureHostConfiguration(configurationBuilder =>
        {
            configurationBuilder.AddCommandLine(args);
        })
        .ConfigureAppConfiguration((hostingContext, configApp) =>
        {
            var env = hostingContext.HostingEnvironment;
            Console.WriteLine(env.EnvironmentName);
        })
        .UseConsoleLifetime();

    return builder;
}

public static async Task Main(string[] args)
{
     var host = CreateDefaultBuilder(args)
                        .ConfigureServices((hostContext, services) =>
                        {
                            services.Configure<HostOptions>(option =>
                            {
                                option.ShutdownTimeout = System.TimeSpan.FromSeconds(20);
                            });

                            services.AddLogging();

                            services.AddSimpleInjector(container, options =>
                            {
                                // Hooks hosted services into the Generic Host pipeline while resolving them through Simple Injector
                                options.AddHostedService<Worker>();

                                // Allows injection of ILogger & IStringLocalizer dependencies into application components
                                options.AddLogging();
                                // options.AddLocalization();
                            });
                        })
                        .Build()
                        .UseSimpleInjector(container);

     config.Build();
     await host.RunAsync();
}

我正在使用 UseConsoleLifetime 和 docker 来运行应用程序,它能够运行,但似乎无法优雅地关闭。

我通过 PowerShell 的 docker stop 命令向我的应用程序发出优雅停止信号。

然而,与我的控制台应用程序不同,在控制台中按下控制+C时,应用程序并没有收到该停止命令,10秒后被强制终止。

请问我的问题如下:

  1. 我如何检测 docker 关闭命令?
  2. 我如何注册两种关闭方法(通过控制台或 docker),具体取决于我调用的方式(有时我可能会直接在 Visual Studio 中作为控制台进行调试,而大多数情况下我会通过 docker 使用,但自动注册两种情景会很好)?

编辑和更新

我看到回复中提到要捕获 AppDomain.CurrentDomain.ProcessExit

对于我的 worker BackgroundService,接口是这样的:

public class Worker : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
             logger.LogInformation("running at: {time} - stoppingToken {stoppingToken}", DateTimeOffset.Now, stoppingToken.IsCancellationRequested);
             await Task.Delay(1000, stoppingToken);
        }
    }
}

使用 UseConsoleLifetime 时,每当发送 ctrl+c 时,stoppingToken 就会被设置。

在 docker 中使用相同的代码(包括 UseConsoleLifetime)时,stoppingToken 没有被设置。

注意我无法访问此令牌源以执行取消操作。

如果我注册到 AppDomain.CurrentDomain.ProcessExit,我如何使用它来设置 stoppingToken(而不是创建自己的 stopping token source,尽管可以这样做,但尽可能避免)。

docker stop


你尝试过这个了吗? - Guru Stron
看起来很好,谢谢。Domain.CurrentDomain.ProcessExit可以与UseConsoleLifetime()并行运行吗?或者有没有特定的方法来检测是作为控制台还是通过Docker运行以便进行注册? - morleyc
不确定,但您可以尝试订阅System.Console.CancelKeyPress事件。 - Guru Stron
您不需要注册ProcessExit或任何其他事件。 UseConsoleLifetime()监听Ctrl + C,SIGINT和SIGTERM - 它已经监视进程终止。当您运行docker stop时,SIGTERM会发送到容器的根进程。那是您的应用程序还是另一个应用程序?您如何构建和运行主机?.Build().RunAsync()?还是其他什么? - Panagiotis Kanavos
你的BackgroundService代码是什么样子的?当终止被信号化时,通过ExecuteAsync传递的CancellationToken也会被信号化。你的代码应该监视它,并在它被触发时快速退出。 - Panagiotis Kanavos
@PanagiotisKanavos,确实是使用await Build().RunAsync()出现了问题,我已经更新了我的问题以反映代码。使用RunAsync和void Main()并使用host.Run(),不幸的是,我的代码没有设置stoppingToken(而当作为控制台运行时,相同的代码可以正常工作)。 - morleyc
1个回答

5

docker stop 命令向容器内主进程发送 SIGTERM 信号。为了处理这个信号并优雅地停止容器,您需要捕获此信号并执行适当的终止代码。这个问题解答描述了如何附加一个事件处理程序来响应此信号。

请注意,如果您不捕获此信号,docker会在超时后(默认为10秒)强制终止容器。

为了同时处理这两种情况,您可以将任何清理代码提取到一个函数中以优雅地关闭,并从两个处理程序中调用它。


谢谢Orphid,一旦信号被捕获,您有任何想法如何设置传递到工作程序运行函数的CancellationToken stoppingToken吗? - morleyc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接