我有一个带有托管服务的.NET Core 3.1应用程序,该服务在Windows上作为控制台应用程序运行。
如果发生错误,我尝试使用Environment.Exit(1)
终止工作进程。
现在的问题是,如果在Enviroment.Exit()
中的任何await
之前调用ExecuteAsync
,则应用程序不会终止。它记录Waiting for the host to be disposed. Ensure all 'IHost' instances are wrapped in 'using' blocks.
,然后无限期挂起。
当我在致电Enviroment.Exit()
之前等待任何事情时,它也会记录下来,但是会按预期终止。
这是我可以重现该问题的最简单的代码。
NotTerminatingWorker
永远挂起,TerminatingWorker
终止。唯一的区别是很小的Task.Delay
:
public class Program {
public static async Task Main(string[] args) {
using var host = CreateHostBuilder(args).Build();
await host.RunAsync();
}
public static IHostBuilder CreateHostBuilder(string[] args) {
return Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) => { services.AddHostedService<NotTerminatingWorker>(); });
}
}
public class NotTerminatingWorker : BackgroundService {
protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
Environment.Exit(1);
}
}
public class TerminatingWorker : BackgroundService {
protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
await Task.Delay(1);
Environment.Exit(1);
}
}
我希望两者的行为方式相同,但事实并非如此。
任何对此的解释将不胜感激!
更新:该应用程序应该既可以作为控制台应用程序运行,也可以作为Windows服务运行。如果崩溃,则需要非零返回码来重新启动它。 而且显然Windows不会重新启动以代码0退出的服务。
答案 0 :(得分:9)
我相信您看到的行为是.NET Core运行时启动方式的副作用:它为每个后台工作程序调用{{1}},然后等待它完成。因此,同步ExecuteAsync
可能会引起问题。我使用ExecuteAsync
来解决此问题。
如果发生错误,我正在尝试使用Environment.Exit(1)终止工作进程。
我建议完全不使用Task.Run
。相反,可以通过注入Environment.Exit
并调用IHostApplicationLifetime
来进行受控关闭。这将为您的每个后台服务触发StopApplication
,并且如果它们忽略了它们,它们将在超时后被强制终止。