Windows Services are useful for various reasons. Using the singleton implementation to wrap up a hardware device has proven very useful to collect data for example. Another main use is to create daemons that poll network sensors and collect data and stuff it into a database.
What if your daemon has a rare bug that you cannot replicate consistently? Well, as tech support always tells you to reboot as a first line of defense. How can you get a service to restart itself? Why would I want to do this you ask? Well for the sensor daemon for example, it spins up a bunch of threads that have different drivers. I had a problem where some extremely rare bug was crashing my service, and I could not figure out how to debug it.
Now that I am more wise I would probably go in and improve exception handling and logging and maybe figure it out... But easier just to restart the thing, to kill all the threads, and spin them back up again.
Initially, I used windows tasks externally to run a batch file, that called "net stop service" then "net start service". This worked fine, until the IT department changed some security or group policy. This caused those commands to fail randomly. The evidence in the task scheduler history showed that on occasion for some unknown reason cmd.exe would return error code 2 (file not found). Hmm.
So I revisited the thought, how do I have the service restart itself. Duh, you insert a timer... I tested this out and it works fine.
Update: I changed to a System.Threading.Timer because the System.Timers.Timer eats up exceptions... Now the timer will pass the exception on, and they will end up in the Windows Application log.
This also shows an example of how to write to the Windows Application log.
using System;
using System.Diagnostics;
using System.ServiceProcess;
using System.Threading;
using DaemonDLL;
namespace DaemonService
{
public partial class DaemonService : ServiceBase
{
private DaemonClass _daemon;
private readonly System.Threading.Timer _timer;
private EventLog _eventLog;
private int _delay = 15 * 60 * 1000; // 15 minutes
private int _monitorWait = 30 * 1000; // 30 seconds
private object _guard = new object();
public DaemonService()
{
InitializeComponent();
_eventLog = new EventLog();
if (!EventLog.SourceExists("DaemonService"))
{
EventLog.CreateEventSource("DaemonService", "Application");
}
_eventLog.Source = "DaemonService";
_eventLog.Log = "Application";
_daemon = new DaemonClass();
_timer = new System.Threading.Timer(Timer_Elapsed);
}
public void Timer_Elapsed(object sender)
{
if (Monitor.TryEnter(_guard, _monitorWait))
{
try
{
_timer.Change(Timeout.Infinite, Timeout.Infinite);
try
{
_daemon.Stop();
}
catch (Exception ex)
{
_eventLog.WriteEntry("DaemonService(): Timer_Elapsed(): Stop(): Exception: " + ex.Message + " " + DateTime.Now);
}
try
{
_daemon.Start();
}
catch (Exception ex)
{
_eventLog.WriteEntry("DaemonService(): Timer_Elapsed(): Start(): Exception: " + ex.Message + " " + DateTime.Now);
}
_timer.Change(_delay, Timeout.Infinite);
_eventLog.WriteEntry("DaemonService(): Service Restarted Automatically (15min intervals)! " + DateTime.Now);
}
catch { }
finally { Monitor.Exit(_guard); }
}
else
{
_eventLog.WriteEntry("DaemonService(): Timer_Elapsed(): Could Not Enter Monitor!?! " + DateTime.Now);
}
}
protected override void OnStart(string[] args)
{
if (Monitor.TryEnter(_guard, _monitorWait))
{
try
{
_daemon.Start();
_timer.Change(_delay, Timeout.Infinite);
}
catch (Exception ex)
{
_eventLog.WriteEntry("DaemonService(): OnStart(): Exception: " + ex.Message + " " + DateTime.Now);
}
finally
{
_eventLog.WriteEntry("DaemonService(): Service Started! " + DateTime.Now);
Monitor.Exit(_guard);
}
}
else
{
_eventLog.WriteEntry("DaemonService(): OnStart(): Could Not Enter Monitor!?! " + DateTime.Now);
}
}
protected override void OnStop()
{
if (Monitor.TryEnter(_guard, _monitorWait))
{
try
{
_timer.Change(Timeout.Infinite, Timeout.Infinite);
_daemon.Stop();
}
catch (Exception ex)
{
_eventLog.WriteEntry("DaemonService(): OnStop(): Exception: " + ex.Message);
}
finally
{
_eventLog.WriteEntry("DaemonService(): Service Stopped! " + DateTime.Now);
Monitor.Exit(_guard);
}
}
else
{
_eventLog.WriteEntry("DaemonService(): OnStop(): Could Not Enter Monitor!?! " + DateTime.Now);
}
}
}
}
using System;
using System.Diagnostics;
using System.ServiceProcess;
using System.Threading;
using DaemonDLL;
namespace DaemonService
{
public partial class DaemonService : ServiceBase
{
private DaemonClass _daemon;
private readonly System.Threading.Timer _timer;
private EventLog _eventLog;
private int _delay = 15 * 60 * 1000; // 15 minutes
private int _monitorWait = 30 * 1000; // 30 seconds
private object _guard = new object();
public DaemonService()
{
InitializeComponent();
_eventLog = new EventLog();
if (!EventLog.SourceExists("DaemonService"))
{
EventLog.CreateEventSource("DaemonService", "Application");
}
_eventLog.Source = "DaemonService";
_eventLog.Log = "Application";
_daemon = new DaemonClass();
_timer = new System.Threading.Timer(Timer_Elapsed);
}
public void Timer_Elapsed(object sender)
{
if (Monitor.TryEnter(_guard, _monitorWait))
{
try
{
_timer.Change(Timeout.Infinite, Timeout.Infinite);
try
{
_daemon.Stop();
}
catch (Exception ex)
{
_eventLog.WriteEntry("DaemonService(): Timer_Elapsed(): Stop(): Exception: " + ex.Message + " " + DateTime.Now);
}
try
{
_daemon.Start();
}
catch (Exception ex)
{
_eventLog.WriteEntry("DaemonService(): Timer_Elapsed(): Start(): Exception: " + ex.Message + " " + DateTime.Now);
}
_timer.Change(_delay, Timeout.Infinite);
_eventLog.WriteEntry("DaemonService(): Service Restarted Automatically (15min intervals)! " + DateTime.Now);
}
catch { }
finally { Monitor.Exit(_guard); }
}
else
{
_eventLog.WriteEntry("DaemonService(): Timer_Elapsed(): Could Not Enter Monitor!?! " + DateTime.Now);
}
}
protected override void OnStart(string[] args)
{
if (Monitor.TryEnter(_guard, _monitorWait))
{
try
{
_daemon.Start();
_timer.Change(_delay, Timeout.Infinite);
}
catch (Exception ex)
{
_eventLog.WriteEntry("DaemonService(): OnStart(): Exception: " + ex.Message + " " + DateTime.Now);
}
finally
{
_eventLog.WriteEntry("DaemonService(): Service Started! " + DateTime.Now);
Monitor.Exit(_guard);
}
}
else
{
_eventLog.WriteEntry("DaemonService(): OnStart(): Could Not Enter Monitor!?! " + DateTime.Now);
}
}
protected override void OnStop()
{
if (Monitor.TryEnter(_guard, _monitorWait))
{
try
{
_timer.Change(Timeout.Infinite, Timeout.Infinite);
_daemon.Stop();
}
catch (Exception ex)
{
_eventLog.WriteEntry("DaemonService(): OnStop(): Exception: " + ex.Message);
}
finally
{
_eventLog.WriteEntry("DaemonService(): Service Stopped! " + DateTime.Now);
Monitor.Exit(_guard);
}
}
else
{
_eventLog.WriteEntry("DaemonService(): OnStop(): Could Not Enter Monitor!?! " + DateTime.Now);
}
}
}
}