0
votes

So, I have a basic timer set to wake a windows service every minute

Timer timer = new Timer();
timer.Interval = 1000 * 60; // 60 seconds
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
timer.Start();

It works most of the time, but I noticed about every hour it will increase the interval of elapsed time in 1 second:

[...]
Service is recall at 9/25/2019 1:26:52 AM
Service is recall at 9/25/2019 1:27:52 AM
Service is recall at 9/25/2019 1:28:52 AM
Service is recall at 9/25/2019 1:29:52 AM
Service is recall at 9/25/2019 1:30:53 AM
Service is recall at 9/25/2019 1:31:53 AM
Service is recall at 9/25/2019 1:32:53 AM
[...]

This caused the service to skip an service recall when minute changed:

Service is recall at 9/20/2019 2:38:59 AM
Service is recall at 9/20/2019 2:40:00 AM

Service was not recall at 2:39.

I think it happens because timer will wake up after elapsed time, not necessarily at the exact time the interval is met, and that is ok (I don't need huge precision, as long as the service is awaken every minute). I just don't want the interval between calls to be incremented by 1 second every hour or so.

I tried to calculate a new interval (instead of 60000 milliseconds) to correct elapsed time, but it is not uniform.

Any ideas on how to prevent this from happening?

1
You cannot rely that your event handler will be called exactly once in every minute. A better way would be to use a smaller interval (say, 1 second) and remember the time of the last call. Then perform the desired action only when the minute changed relative to the remembered time stamp. - Klaus Gütter

1 Answers

0
votes

The timer fires every minute as you expect but the timer does not take in to account the amount of time it takes to process the information in the function. If you need it to fire every minute, you will need to calculate the amount of time it took to process your information and then change the amount of time before the timer fires:

private void OnElapsedTime()
{
    Stopwatch watch = new Stopwatch();
    watch.Start();

    //DO YOUR WORK HERE

    Timer.Change(Math.Max(0, 60000 - watch.ElapsedMilliseconds));

    watch.Stop();
}

This is not 100% precise but should give you the desired results.