You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET BackgroundService停止后重启抛出System.OperationCanceledException问题

BackgroundService重启报错原因及正确方式

问题原因

  • .NET的IHost实例是单次生命周期设计,调用StopAsync()后,宿主会完成内部资源释放、终止所有托管服务,并将自身状态标记为已停止/已处置。此时宿主内部的取消令牌、服务容器等核心组件已处于终止状态,无法再次启动,调用StartAsync()必然抛出System.OperationCanceledException。
  • 原代码中host.RunAsync()未使用await,会导致宿主启动逻辑与后续停止/重启逻辑并行执行,加剧状态冲突,但核心问题仍是IHost不可复用。

正确重启方式

不能复用同一个IHost实例,每次重启都需要销毁旧宿主,重新构建新的宿主实例并启动。修改后的代码示例如下:

Program.cs

while (true)
{
    // 每次循环创建全新的宿主实例
    using IHost host = Host.CreateDefaultBuilder(args)
        .ConfigureServices(services =>
        {
            services.AddHostedService<TestWorker>();
        })
        .Build();

    // 启动宿主并等待其运行
    var hostTask = host.RunAsync();

    Thread.Sleep(5000);
    await host.StopAsync();
    // 等待宿主完全停止并释放资源
    await hostTask;
    Thread.Sleep(5000);
}

TestWorker.cs(保持不变)

public class TestWorker : BackgroundService {
  private readonly ILogger<TestWorker> _logger;

  public TestWorker(ILogger<TestWorker> logger) {
    _logger = logger;
  }

  protected override async Task ExecuteAsync(CancellationToken stoppingToken) {
    while (!stoppingToken.IsCancellationRequested) {
      _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
      await Task.Delay(1000, stoppingToken);
    }
  }
}

关键说明

  • 使用using声明宿主,确保每次循环结束后自动释放宿主资源,避免内存泄漏。
  • 每次重启都重新构建IHost,保证每次启动都是全新的生命周期,彻底规避旧实例的状态污染。
  • await hostTask确保宿主完全停止并完成资源释放后,再进入下一次重启循环,保证状态切换的完整性。

内容的提问来源于stack exchange,提问作者Xorcist

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 02:31:01