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

IIS部署REST服务中Singleton定时HostedService运行异常问题

IIS部署的定时后台服务问题解决

问题1:仅当有请求时服务才运行

这是IIS默认的应用池闲置回收机制导致的——默认20分钟无请求就会回收进程,后台服务跟着终止。按下面步骤改配置:

  • 打开IIS管理器,找到你的应用对应的应用池
  • 右键选「高级设置」
  • 把「闲置超时(分钟)」改成0(彻底禁用闲置回收)
  • 把「定期时间间隔(分钟)」也改成0(禁用定时回收)
  • 把「启动模式」设为AlwaysRunning(让应用池启动后立刻运行,不用等首次请求)

问题2:每小时生成多条日志

核心原因是服务被多次实例化,或者应用池频繁重启导致多个Timer同时工作。解决办法:

  1. 确认服务注册正确:在Program.cs里必须用AddHostedService注册,这个方法默认把IHostedService注册为单例,确保只有一个实例:
builder.Services.AddHostedService<TimedHostedService>();
  1. 避免重复创建Timer:在StartAsync里加个判断,防止重复初始化Timer:
public Task StartAsync(CancellationToken stoppingToken)
{
    if (_timer != null)
    {
        _logger.LogWarning("Timer already exists, skip initialization");
        return Task.CompletedTask;
    }
    
    _timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromHours(1));
    _logger.LogInformation("Timed Hosted Service started");
    return Task.CompletedTask;
}

额外优化建议

  • 别在Timer回调里直接做耗时操作(比如数据库检查),线程池线程被阻塞会影响其他请求。改成异步执行:
private void DoWork(object? state)
{
    // 用后台任务跑异步逻辑,不阻塞Timer回调
    _ = RunDatabaseCheckAsync();
}

private async Task RunDatabaseCheckAsync()
{
    var count = Interlocked.Increment(ref executionCount);
    try
    {
        _logger.LogInformation("Starting database check. Count: {Count}", count);
        // 这里写你的数据库检查代码
        await YourDatabaseCheckMethodAsync();
        _logger.LogInformation("Database check done. Count: {Count}", count);
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "Database check failed. Count: {Count}", count);
    }
}
  • 停止服务时要处理未完成的任务,避免中途中断数据库操作:
private CancellationTokenSource? _taskCts;

public Task StartAsync(CancellationToken stoppingToken)
{
    _taskCts = CancellationTokenSource.CreateLinkedTokenSource(stoppingToken);
    // 原有Timer初始化代码
}

private async Task RunDatabaseCheckAsync()
{
    try
    {
        // 把取消令牌传给数据库操作,支持中途取消
        await YourDatabaseCheckMethodAsync(_taskCts.Token);
    }
    catch (OperationCanceledException)
    {
        _logger.LogInformation("Database check was canceled");
    }
}

public async Task StopAsync(CancellationToken stoppingToken)
{
    _timer?.Change(Timeout.Infinite, 0);
    _taskCts?.Cancel();
    // 等待正在执行的任务收尾
    await Task.Delay(1000);
    _logger.LogInformation("Timed Hosted Service stopped");
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 17:20:57