我正在开发一个主要运行以下代码的 Windows 服务:
public class ServiceController
{
private FundsEngine _fundsEngine;
protected override void OnStart(string[] args)
{
var logsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "logs");
if (Directory.Exists(logsPath) == false)
{
Directory.CreateDirectory(logsPath);
}
_fundsEngine = new FundsEngine();
_fundsEngine.Start();
}
}
该服务可以启动“引擎”,这些引擎只是使用定时器在指定时间间隔内执行代码的类。
以下类是使用 System.Threading.Timer
每 5 秒调用一次回调 OnTick()
的引擎示例。
public class FundsEngine
{
private System.Threading.Timer _timer;
private static Logger _logger = LogManager.GetCurrentClassLogger();
public void Start()
{
_logger.Trace("Begin Start");
try
{
// details omitted
_timer = new Timer(OnTick);
_timer.Change(5000, Timeout.Infinite);
}
catch (Exception exception)
{
_logger.ErrorException("Error in Start.", exception);
}
finally
{
_logger.Trace("End Start");
}
}
private void OnTick(object state)
{
_logger.Trace("Begin Tick");
try
{
// do stuff
_timer.Change(5000, Timeout.Infinite);
}
catch (Exception exception)
{
_logger.ErrorException("Error in Tick. ", exception);
}
finally
{
_logger.Trace("End Tick");
}
}
}
如下面的日志所示,定时器按预期工作,每 5 秒调用一次 OnTick()
方法。
2013-05-14 16:27:01.2261|TRACE|Begin Start
2013-05-14 16:27:03.8514|TRACE|End Start
2013-05-14 16:27:08.8569|TRACE|Begin Tick
2013-05-14 16:27:08.8709|TRACE|End Tick
2013-05-14 16:27:13.8734|TRACE|Begin Tick
2013-05-14 16:27:13.8734|TRACE|End Tick
2013-05-14 16:27:18.8809|TRACE|Begin Tick
2013-05-14 16:27:18.8809|TRACE|End Tick
2013-05-14 16:27:23.8894|TRACE|Begin Tick
2013-05-14 16:27:23.8894|TRACE|End Tick
2013-05-14 16:27:28.8969|TRACE|Begin Tick
2013-05-14 16:27:28.8969|TRACE|End Tick
2013-05-14 16:27:33.9044|TRACE|Begin Tick
2013-05-14 16:27:33.9044|TRACE|End Tick
如果在 OnTick()
方法中捕获到异常,我希望它会被记录下来,并且服务会继续运行,这样 OnTick()
方法将在 5 秒后再次调用。然而,情况并非如此,因为在处理异常后,回调不会再次调用。这是为什么?
2013-05-14 16:29:03.8574|TRACE|Begin Start
2013-05-14 16:29:03.8574|TRACE|End Start
2013-05-14 16:29:08.8709|TRACE|Begin Tick
2013-05-14 16:29:09.9750|ERROR|Error in Tick. System.Net.Sockets.SocketException (0x80004005): No connection could be made because the target machine actively refused it 127.0.0.1:22
2013-05-14 16:29:09.9750|TRACE|End Tick
最佳答案
_timer.Change(5000, Timeout.Infinite);
您没有创建周期计时器,为 period 参数传递了 Infinite。计时器只会调用一次 OnTick()。然而,代码非常不完整,唯一可行的方法是再次调用 Change() 为计时器充电。
此 Change() 调用被异常绕过的几率很高。如果您想让它继续运行,那么此 Change() 调用属于 finally block 。虽然这样做实际上不是一个好主意,但进程状态被破坏并且它会再次崩溃的可能性非零。一遍又一遍。你至少应该对此采取对策,并计算连续崩溃的次数,当它反复轰炸时放弃。
关于c# - 为什么在捕获到 Exception 时停止调用 Timer 回调?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16566449/