ASP.NET Web API(.NET5)按CTRL+C时IHostedService的StopAsync未触发问题
问题原因
- 你当前直接实现
IHostedService时没有正确追踪后台任务的生命周期:StartAsync中Task.Factory.StartNew搭配async lambda返回的是Task<Task>类型,你直接返回外层Task后,宿主会认为托管服务启动完成,不会追踪内层实际执行业务逻辑的Task状态,应用退出时不会等待你的后台任务结束,直接就终止进程了。 Run方法中捕获异常/取消后直接调用_appLifetime.StopApplication(),会触发应用强制终止流程,跳过部分优雅清理逻辑。- 你当前的服务注册存在笔误:实现的托管服务类是
MyHostedService,但注册的是CacheManagerHostedService,如果实际代码没对齐也会导致生命周期逻辑异常。 - 你在
StopAsync中输出的是Debug级别的日志,如果项目默认日志配置过滤了Debug级别,也会看不到对应输出。
需修改的内容
1. 优先继承BackgroundService抽象类实现托管服务
.NET 自带的BackgroundService已经封装了后台任务生命周期的管理逻辑,不需要自己手动处理StartAsync的线程创建、任务追踪逻辑,能避免绝大多数生命周期问题。
2. 调整后台任务逻辑,移除不必要的强制终止调用,在StopAsync中等待任务退出
修改后的托管服务代码示例:
public class MyHostedService : BackgroundService { private readonly ILogger<MyHostedService> _logger; public MyHostedService(ILogger<MyHostedService> logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { try { // 原来的长时间运行代码,直接用stoppingToken判断退出信号即可 while (!stoppingToken.IsCancellationRequested) { // 你的业务逻辑 await Task.Delay(1000, stoppingToken); } } catch (OperationCanceledException) { _logger.LogInformation("后台任务收到取消信号,即将退出"); } catch (Exception ex) { _logger.LogError(ex, "后台任务出现未处理异常"); } } public override async Task StopAsync(CancellationToken cancellationToken) { // 这里可以先写你的清理逻辑 _logger.LogInformation("StopAsync开始执行,正在清理资源"); // 调用基类的StopAsync,等待后台任务正常退出 await base.StopAsync(cancellationToken); _logger.LogInformation("StopAsync执行完成"); } }
3. 修正服务注册逻辑
对齐注册的服务类型和实际实现类:
services.AddHostedService<MyHostedService>();
4. 验证日志配置
如果需要看到Debug级别的日志,确认appsettings.json中的日志配置没有过滤MyHostedService的Debug级别输出,测试阶段可以先把日志级别改成Information验证StopAsync是否执行。
内容的提问来源于stack exchange,提问作者mnj
相关产品推荐
相关产品推荐

