如何让Windows在.NET服务故障时自动重启该服务
解决方案
核心问题是:当BackgroundService在await后抛出未处理异常时,.NET Host会以零退出码优雅停止进程,Windows服务管理器将其判定为正常停止,不会触发sc failure配置的重启。要让Windows自动重启,必须让进程以非零退出码终止。
方法一:捕获BackgroundService异常并强制非零退出
步骤1:在Host启动时订阅停止事件
在Main函数中,构建Host后订阅ApplicationStopped事件,检测是否因未处理异常导致停止,若为异常则强制进程退出并返回非零码:
var host = Host.CreateDefaultBuilder(args) .ConfigureServices(services => { services.AddHostedService<MyHostedService>(); }) .Build(); // 监听服务停止事件 host.Services.GetRequiredService<IHostApplicationLifetime>().ApplicationStopped.Register(() => { var myService = host.Services.GetService<MyHostedService>(); if (myService?.UnhandledException != null) { // 非零退出码触发Windows服务重启 Environment.Exit(1); } }); await host.RunAsync();
步骤2:在BackgroundService中保存未处理异常
修改你的MyHostedService类,将未捕获的异常保存到公共属性中:
public class MyHostedService : BackgroundService { public Exception UnhandledException { get; private set; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { try { // 你的业务逻辑(包含第三方库调用和await操作) while (!stoppingToken.IsCancellationRequested) { await ThirdPartyLibrary.BuggyMethodAsync(); await Task.Delay(5000, stoppingToken); } } catch (Exception ex) { UnhandledException = ex; // 抛出异常让Host触发停止流程 throw; } } }
方法二:异常发生时直接强制退出进程
如果不需要Host完成优雅清理,可在BackgroundService捕获异常后直接调用Environment.Exit(1)终止进程:
public class MyHostedService : BackgroundService { private readonly ILogger<MyHostedService> _logger; public MyHostedService(ILogger<MyHostedService> logger) { _logger = logger; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { try { await ThirdPartyLibrary.BuggyMethodAsync(); await Task.Delay(5000, stoppingToken); } catch (Exception ex) { _logger.LogError(ex, "第三方库触发Bug,即将终止进程"); // 直接退出进程,返回非零码 Environment.Exit(1); } } } }
验证sc配置正确性
确保你的故障重启配置命令语法正确(注意reset=后必须有空格):
sc failure "MyService" reset= 30 actions= restart/5000
该配置表示:30秒内无故障则重置故障计数,故障后5秒自动重启服务。
内容的提问来源于stack exchange,提问作者sefor
相关产品推荐
相关产品推荐

