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
相关产品推荐
相关产品推荐

