SCM 未重启 BackgroundService
BackgroundService not restarted by SCM
目标:
运行 Windows 上的 .net 6.0 BackgroundService,当发生未处理的异常时自动重新启动。
最小示例:
Program.cs
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddHostedService<Worker>();
})
.UseWindowsService(options =>
{
options.ServiceName = "ASampleService";
})
.Build();
await host.RunAsync();
Worker.cs
namespace SampleWindowsService
{
public class Worker : BackgroundService
{
[...]
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
throw new Exception();
}
}
}
}
sc 故障配置
sc failure ASampleService reset=0 actions= restart/5000
预期行为
服务应在启动 10 秒后崩溃,然后在崩溃 5 秒后重新启动。它应该无限期地这样做。系统事件日志应包含 ASampleService 崩溃并将在 5000 毫秒内由服务控制管理器重新启动的日志行。
实际行为
服务崩溃并在应用程序事件日志中生成日志行“服务已成功停止”并且永远不会重新启动。
问题
我猜“已成功停止”记录行是问题的核心。根据 this article :
“A service is considered failed when it terminates without reporting a status of SERVICE_STOPPED to the service controller.”
但是,我还没有找到阻止服务“成功停止”的方法,即使覆盖 BackgroundService 的 StopAsync 函数或 IHostApplicationLifecycle 的 OnStop 并在那里抛出异常,也没有阻止该日志行。
我一直在深入研究源代码以了解正在发生的事情,我开始认为我可能需要使用较低级别的抽象来使其工作。但是,如果这里有人知道如何让它发挥作用,我很想听听您的方法。
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
while (!stoppingToken.IsCancellationRequested)
{
// simulate some work here
await Task.Delay(TimeSpan.FromSeconds(5));
// something went wrong
throw new Exception();
}
}
catch
{
// prevent "Stopped successfully"
Environment.Exit(1);
}
}
.net 文档中的文章也将更新。您可能还想将退出代码设置为异常的 HResult。
使用此代码,scm 将重新启动服务,系统日志将显示正确的消息:
The SampleService service terminated unexpectedly. It has done this 1 time(s). The following corrective action will be taken in 5000 milliseconds: Restart the service.
目标:
运行 Windows 上的 .net 6.0 BackgroundService,当发生未处理的异常时自动重新启动。
最小示例:
Program.cs
IHost host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddHostedService<Worker>();
})
.UseWindowsService(options =>
{
options.ServiceName = "ASampleService";
})
.Build();
await host.RunAsync();
Worker.cs
namespace SampleWindowsService
{
public class Worker : BackgroundService
{
[...]
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
throw new Exception();
}
}
}
}
sc 故障配置
sc failure ASampleService reset=0 actions= restart/5000
预期行为
服务应在启动 10 秒后崩溃,然后在崩溃 5 秒后重新启动。它应该无限期地这样做。系统事件日志应包含 ASampleService 崩溃并将在 5000 毫秒内由服务控制管理器重新启动的日志行。
实际行为
服务崩溃并在应用程序事件日志中生成日志行“服务已成功停止”并且永远不会重新启动。
问题
我猜“已成功停止”记录行是问题的核心。根据 this article :
“A service is considered failed when it terminates without reporting a status of SERVICE_STOPPED to the service controller.”
但是,我还没有找到阻止服务“成功停止”的方法,即使覆盖 BackgroundService 的 StopAsync 函数或 IHostApplicationLifecycle 的 OnStop 并在那里抛出异常,也没有阻止该日志行。
我一直在深入研究源代码以了解正在发生的事情,我开始认为我可能需要使用较低级别的抽象来使其工作。但是,如果这里有人知道如何让它发挥作用,我很想听听您的方法。
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
try
{
while (!stoppingToken.IsCancellationRequested)
{
// simulate some work here
await Task.Delay(TimeSpan.FromSeconds(5));
// something went wrong
throw new Exception();
}
}
catch
{
// prevent "Stopped successfully"
Environment.Exit(1);
}
}
.net 文档中的文章也将更新。您可能还想将退出代码设置为异常的 HResult。
使用此代码,scm 将重新启动服务,系统日志将显示正确的消息:
The SampleService service terminated unexpectedly. It has done this 1 time(s). The following corrective action will be taken in 5000 milliseconds: Restart the service.