I am working on a Windows Service that essentially runs the following code:
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();
}
}
The service can start up "Engines" which are just classes that use Timers to execute code on a specified interval.
The following class is an example of an Engine that uses System.Threading.Timer to invoke a callback, OnTick(), every 5 seconds.
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");
}
}
}
As shown in the log below, the Timer works as expected, invoking the OnTick() method every 5 seconds.
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
In the event that an Exception is caught in the OnTick() method, my expectation is that it will be logged, and the service will continue running, such that the OnTick() method will be invoked again in 5 seconds. However, this is not the case, as the callback is never invoked again after the Exception is handled. Why is this?
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);
You didn't create a period timer, passing Infinite for the period argument. The timer will call OnTick() only once. Code is however very incomplete, the only way it could work is when it calls Change() again to recharge the timer.
So high odds that this Change() call is getting bypassed by the exception. If you want to keep it going then this Change() call belongs in the finally block. Although it is not actually a good idea to do this, non-zero odds that the process state is corrupted and it will just crash again. Over and over. You should at least take a countermeasure against this and also count the number of consecutive crashes, giving up when it just bombs repeatedly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With