I’m trying to write a service in c# that should be run on a given interval (a timeout) from a given date. If the date is in the future the service should wait to start until the date time is reached.
Example:
-
If I set a timeout to be 1 hour from 21:00:00 I want the program to run every hour
-
If I set a timeout to be 1 hour from 3999.01.01 21:00:00 I want the program to until date and from then run each hour
I have sort of achieved that with the following code, but it has some problems!
-
When I install the service (with installutil) the service is marked as starting because of the ‘Thread.Sleep()’. This service appears to be hanging and is “installing” until started.
-
The code inside ‘ServiceTimer_Tick()’ might take longer than the expected timeout. How can I prevent the timer stack from increasing if that happens?
Alternatives I’ve thought of :
-
include using the ‘timeout.Interval’ first time and then resetting it subsequent calls, but it doesn’t feel right.
-
I’ve also considered ditching the entire service idea and compile it as a executable and set up a scheduled tasks.
Shortened example:
public Service()
{
_timeout = new TimeSpan(0,1,0,0);
_timer = new System.Timers.Timer();
_timer.Interval = _timeout.TotalMilliseconds;
_timer.Elapsed += new ElapsedEventHandler(ServiceTimer_Tick);
}
private void ServiceTimer_Tick(object sender, System.Timers.ElapsedEventArgs e)
{
lock (_obj)
{
// Stuff that could take a lot of time
}
}
public static void Main()
{
Run(new Service());
}
protected override void OnStart(string[] args)
{
long current = DateTime.Now.Ticks;
long start = new DateTime(2010,9,15,21,0,0).Ticks;
long timeout = _timeout.Ticks;
long sleep;
if (current > start)
sleep = timeout - ((current % timeout)) + (start % timeout);
else
sleep = start - current;
Thread.Sleep(new TimeSpan(sleep));
_timer.AutoReset = true;
_timer.Enabled = true;
_timer.Start();
}
you have to move the timer logic to a separate thread that you spawn from your OnStart routine. Then your logic cannot interfere with the SCM and the service will start normally.
Edit: Just to elaborate – for this task I don’t think timers work very well, since you are not taking clock corrections into account which could lead to a skew (or even be incorrect if the user manually changes the clock time). That’s why comparing to the clock time in small intervals is imo preferred.
The
Runroutine of that thread could look like this: