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

System.Threading.Timer调用异常:Windows服务定时任务停止执行排查

问题分析与解决措施

你的核心问题是System.Threading.Timer被垃圾回收导致停止触发,同时还有几个潜在风险点需要排查,具体如下:

1. 修复Timer被GC回收的问题

你在OnStart方法中创建的Timer是局部变量,当OnStart执行完毕后,这个变量会失去引用,后续GC会将它回收,Timer自然就停止触发了。

修改方式:把Timer声明为类的成员变量,确保它始终有引用:

namespace Service
{
    public partial class Service: ServiceBase
    {
        // 声明为类成员变量
        private Timer _timer;

        protected override void OnStart(string[] args)
        {
            log("Service Started");
            // 初始化成员变量
            _timer = new Timer(this.OnTimer, null, TimeSpan.FromSeconds(5), TimeSpan.FromSeconds(60));
        }
        
        public void OnTimer(object state)
        {
            log("Function fired"); 

            // do something

            log("Function closed");
        }
        
        protected override void OnStop()
        {
            // 停止并释放Timer资源
            _timer?.Change(Timeout.Infinite, Timeout.Infinite);
            _timer?.Dispose();
            log("Service stopped");
        }
    }
}

2. 捕获回调中的所有未捕获异常

System.Threading.Timer的回调如果抛出未捕获的异常,会直接导致Timer停止触发(.NET Framework环境下),即使你日志里没看到异常,也可能是异常被吞掉了。

给OnTimer方法添加全局异常捕获:

public void OnTimer(object state)
{
    try
    {
        log("Function fired"); 

        // do something

        log("Function closed");
    }
    catch (Exception ex)
    {
        log($"Timer回调异常: {ex.Message}\n{ex.StackTrace}");
        // 这里不要抛出异常,确保Timer能继续触发
    }
}

3. 排查Timer回调执行时长

如果// do something的执行时间超过了Timer的间隔(60秒),会导致回调叠加执行,极端情况下可能引发资源耗尽或系统将Timer标记为异常状态。你可以在日志中记录每次回调的开始和结束时间,计算执行时长:

public void OnTimer(object state)
{
    try
    {
        var startTime = DateTime.Now;
        log($"Function fired at {startTime:yyyy-MM-dd HH:mm:ss}"); 

        // do something

        var endTime = DateTime.Now;
        log($"Function closed at {endTime:yyyy-MM-dd HH:mm:ss}, 耗时: {(endTime - startTime).TotalSeconds:F2}秒");
    }
    catch (Exception ex)
    {
        log($"Timer回调异常: {ex.Message}\n{ex.StackTrace}");
    }
}

如果执行时长接近或超过60秒,需要优化业务逻辑,或者调整Timer间隔,也可以添加锁防止回调重叠:

private readonly object _lockObj = new object();

public void OnTimer(object state)
{
    if (!Monitor.TryEnter(_lockObj))
    {
        log("上一次回调尚未完成,跳过本次执行");
        return;
    }
    try
    {
        // 业务逻辑
    }
    finally
    {
        Monitor.Exit(_lockObj);
    }
}

4. 检查Windows服务系统日志

打开Windows事件查看器,定位到「Windows日志」->「应用程序」,查看是否有服务相关的错误日志,比如服务进程意外终止、权限不足等问题,这些也可能导致Timer停止工作。

5. 确认Timer的状态是否被意外修改

检查你的业务逻辑中是否有代码调用了Timer.Change方法,意外将间隔改为Timeout.Infinite,导致Timer停止触发。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 05:12:44