我有以下默认的通用主机生成器:
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秒后被强制终止。
请问我的问题如下:
- 我如何检测 docker 关闭命令?
- 我如何注册两种关闭方法(通过控制台或 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,尽管可以这样做,但尽可能避免)。
Domain.CurrentDomain.ProcessExit
可以与UseConsoleLifetime()
并行运行吗?或者有没有特定的方法来检测是作为控制台还是通过Docker运行以便进行注册? - morleycSystem.Console.CancelKeyPress
事件。 - Guru StronProcessExit
或任何其他事件。UseConsoleLifetime()
监听Ctrl + C,SIGINT和SIGTERM - 它已经监视进程终止。当您运行docker stop
时,SIGTERM会发送到容器的根进程。那是您的应用程序还是另一个应用程序?您如何构建和运行主机?.Build().RunAsync()
?还是其他什么? - Panagiotis KanavosExecuteAsync
传递的CancellationToken
也会被信号化。你的代码应该监视它,并在它被触发时快速退出。 - Panagiotis Kanavosawait Build().RunAsync()
出现了问题,我已经更新了我的问题以反映代码。使用RunAsync和void Main()
并使用host.Run()
,不幸的是,我的代码没有设置stoppingToken(而当作为控制台运行时,相同的代码可以正常工作)。 - morleyc