由于错误,BackgroundService
我正在使用 Stephen Cleary 的出色解决方法。它有效,但失败时我无法返回非零退出代码。
一个最小的工作示例(与模板一起使用$ dotnet new worker
):
MyBackgroundService.cs
public class MyBackgroundService : BackgroundService {
private readonly IHostApplicationLifetime _lifetime;
public MyBackgroundService(IHostApplicationLifetime lifetime) => _lifetime = lifetime;
protected override Task ExecuteAsync(CancellationToken stoppingToken) => Task.Run(async () => {
try {
while (!stoppingToken.IsCancellationRequested) {
await Task.Delay(1000);
if (Random.Shared.NextDouble() < 0.5) throw new Exception("RANDOM CRASH!");
}
}
catch {
throw; // I can hit a debug breakpoint here
}
finally {
_lifetime.StopApplication();
}
});
}
Program.cs
public class Program {
public static int Main(string[] args) {
try {
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<MyBackgroundService>();
var host = builder.Build();
host.Run();
return 0;
}
catch (Exception) {
return 1; // <----- execution never arrives here
}
}
}
当应用程序崩溃时,我期望退出代码为1
,但实际上它是默认的0
。当我调试时它永远不会进入 catch 块。
可能是什么原因?
这实际上是因为返回的任务
BackgroundService.ExecuteAsync
被忽略了(正如我的博客中所解释的)。因此,即使您关闭主机,异常仍然会被忽略。托管服务无法报告异常或退出代码。您的选择是:
BackgroundService
派生类型,公开其派生类型Task
,并让主循环解析派生类型的实例并等待这些任务。这将观察后台服务的异常。Environment.ExitCode
,类似于我博客上的这段代码。然后你Main
就可以返回了void
。这两种方法都会在应用程序生命周期内进行“最终运行”,因为 .NET 主机并未设计为允许后台服务结果。我自己使用第二个,因为相同的代码适用于工作进程和 SCM 服务。
已接受答案中的解决方法很好。但我选择了懒惰的路线:
MyBackgroundService.cs
Program.cs