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?
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.
Related
I am building an alerter service (windows service) in c#. This service will start and do a few api calls. based on the result I get from the calls and the setting that apply to that user an other method will fire after x amount of time. This goes on until the user stops the service.
The time in between the calls to the methods can be variable. So after startup the first method call can be after 1 min, after that the next call can be after 5 min, the call after that can be after 10 min. All depends on the response I get from the API.
I have been looking into system.timers, but every example i find has a fixed time the event fires so that does not fit my needs.
Define the time variable globally and after each response reset the interval time
FYI
1 Minute = 60000 so for 10 Minutes aTimer.Interval=60000 * 10;
use it like this
//defined globally
System.Timers.Timer aTimer = new System.Timers.Timer();
aTimer.Elapsed+=new ElapsedEventHandler(OnTimedEvent);
//api call goes here
aTimer.Interval=5000; // here you can define the time or reset it after each api call
aTimer.Enabled=true;
Use a one-shot timer, and reset it after every call. I typically use System.Threading.Timer for this:
// When you first create the timer, set it for the initial time
Timer MyTimer = new Timer(TimerCallbackFunction, null, 60000, Timeout.Infinite);
Setting the period to Timeout.Infinite prevents the timer from ticking multiple times. It'll just tick once and then wait indefinitely, or until you restart it.
In your timer callback, do whatever needs to be done and then reset the timer:
void TimerCallbackFunction(object state)
{
// Here, do whatever you need to do.
// Then set the timer for the next interval.
MyTimer.Change(newTimeoutValue, Timeout.Infinite);
}
This prevents multiple concurrent callbacks (if your timeout value is too short), and also lets you specify when the next tick will be.
Assuming I have a windows service which has a timer that is set to run every 6 hours, I would expect it to fire 4 times a day. Let's say : 0000, 0600, 1200 1800. (Military time, same as 00:00, etc...)
If the system goes to sleep at 1000, and wakes at 1700, what happens?
will it fire again at 1900, because it has 2 hours on the timer?
will it fire straight away (because it missed it's 1200 appointment), and then fire again at 2300 (adding it's 6 hours to the current time?)
I've noticed that when the computer goes to sleep, it doesn't fire the OnPause or OnContinue methods.
If anyone can shed some light on the behaviour of the system in the above cases, It'll be great know.
Cheers, and thanks in advance.
As has already been mentioned in the comments: Use the task scheduler instead of timers. See this article for further discussion.
The question of how timers behave during sleep is still interesting, though. In the specific case you mention, option 2. will be the observed behavior. The timer will fire on resume because it missed an event during sleep and subsequently start counting from 0 again The next time it fires will thus be at 23:00. This answer has sample code to support the observation.
In case you want to detect when the system sleeps and resumes, subscribe to the SystemEvents.PowerModeChanged event. This event's PowerModeChangedEventArgs contains a Mode, of which you are interested in Suspend and Resume.
For my needs, I ended up going with a windows service that will check if and when next operation needs to be carried, and simply set the timer to that time.
The windows service will update that time upon resuming from sleep.
The benefits are :
Unaffected by sleep/wake times
no console apps being run by a scheduler.
using NLog (quick tutorial here) and Growl (how to use Growl with NLog tutorial here) to receive notifications on the desktop
having a log on the system as well
Since my case is simple, having the functionality is already in a separate dll, I don't have any issues with stability or memory leaks (and if I do, shame on me). This keeps what I need happening once a day, or once every time the computer wakes up, and doesn't incur extra overhead on the system.
Like Henrik replied and linked, the correct answer is number 2.
I've wrote the following in linqpad, which is similar to the link in the above answer:
static int counter = 0;
static System.Timers.Timer my_timer;
void Main()
{
// Set up a timer to trigger every minute.
my_timer = new System.Timers.Timer();
DateTime now = DateTime.Now;
my_timer.Interval = (60 - now.Second) * 1000; // Fire at beginning of minute
string.Format("First tick in {0} seconds", my_timer.Interval/1000).Dump();
my_timer.Elapsed += OnTimer;
my_timer.Start();
while (counter < 5) { // sleep away until 5 ticks happen
Thread.Sleep(5000);
}
// stop timer and say goodbye
my_timer.Stop();
DateTime.Now.Dump("Finished running, shutting down");
}
// Print time and counter every timer tick
void OnTimer(object sender, System.Timers.ElapsedEventArgs args)
{
if (my_timer.Interval != 60000) // set to one minute after first time
my_timer.Interval = 60000;
DateTime.Now.ToString("HH:mm:ss.fff").Dump("On Timer fired:");
(counter++).Dump("Static counter :");
}
Getting the results:
First tick in: 37 seconds
On Timer fired : 08:47:00.552
Static counter : 0
On Timer fired : 08:48:00.557
Static counter : 1
On Timer fired : 08:49:00.571
Static counter : 2
// Shut computer down for 3 minutes at 08:49:30
On Timer fired : 08:52:33.509
Static counter : 3
On Timer fired : 08:53:33.510
Static counter : 4
Finished running, shutting down
1/09/2014 8:53:38 AM
So, obviously the computer knows it missed a tick, it fires the method once, and continues from there. Note that it only fires once.
But would be happy if someone who knows what happens behind the scenes can shed some more light on this.
I'm writing a code where:
I.)
The user adds "events" during run-time. (To a flowlayoutpanel) These events are turning some LEDs on/off, after "x" time has elapsed and the LED-turning functions are written in a Led-function.cs class.
i.e:
1) Turn left led on After 3500ms
2) Turn right led on After 4000ms
II.)
When the user hits start a timer starts.
// Create timer.
System.Timers.Timer _timer;
_timer = new System.Timers.Timer();
_timer.Interval = (1);
_timer.Elapsed += (sender, e) => { HandleTimerElapsed(LedObject, device, _timer); };
_timer.Start();
III.)
The timer's tick event is raised every millisecond and checks if the user definied time has ellapsed. Im measuring the elapsed time with adding +1 to an integer at every tick event. (NumberOfTicks++;)
//Timer Handle
private void HandleTimerElapsed(Led_Functions LedObject, string device, System.Timers.Timer _timer)
{
NumberOfTicks++;
if (NumberOfTicks >= Start_time[0])
{
LedObject.LeftLED_ONnobutton(device);
}
}
IV.) What I noticed was that when the tick was set to 1. (So the tick event is raised every millisecond) Even if I set 3000ms to the evet the LED actually flashed around 6 seconds.
When the tick was set to 100. (So every 0,1s) then the flash was more accurate (3,5sec or so).
Any Ideas why im having this delay in time?
Or do you have any ideas how could I implement it better?
Thank you!
1ms is a really small interval for CPUs. You cannot ensure your code get called every 1ms especially when the system has some heavy work to do.
A better implement is to use DateTime.Now - startTime to get the time span or use Stopwatch.
private Stopwatch stopwatch = new Stopwatch();
// start the stopwatch:
stopwatch.Start();
// Timer Handle:
numberOfTicks = stopwatch.ElapsedMilliseconds;
I have created a windows service.In which I have set the timer interval for every one minute and so it was triggering for every minute,. But I need to trigger the same for each day..
You can find the code below where I have set the timer interval in OnStart() method..
Code:
protected override void OnStart(string[] args)
{
TraceService("start service");
//handle Elapsed event
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
//This statement is used to set interval to 1 minute (= 60,000 milliseconds)
timer.Interval = 86400000;
//enabling the timer
timer.Enabled = true;
}
This post is quite old but I think it's worth mentioning that instead of using a magic number like 86400000 it's better to use something like new TimeSpan(1, 0, 0, 0).TotalMilliseconds , so that if someone needs to change it they will know what should be changed.
So, couple of things regarding your post:
First, it does not state what is the problem!
Technically, Timer supports a timer interval of about 25 days.
So, your code should work.
If you want to exceed 25 days and you are not concerned about thread safety, I suggest you go to System.Threading.Timer.
More info here
Since, your service runs as a windows based service, i suggest you go to System.Threading.Timer.
In C# now you can use TimeSpan class to get total milliseconds in day to set a per day timer.
var totalMilliSecondsPerDay = TimeSpan.FromDays(1).TotalMilliseconds;
var timer = new Timer(totalMilliSecondsPerDay);
I am trying to get a timer run every minute in sync with the system clock (00:01:00, 00:02:00, 00:03:00, etc). Will the following code produce a stable timer? I've tried running it. The timer does precisely run every min. But the question is will it start to wander off, say, after several months?
private System.Timers.Timer timer;
public frmMain()
{
timer = new System.Timers.Timer();
timer.AutoReset = false;
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
timer.Interval = GetInterval();
timer.Start();
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//Do processing
timer.Interval = GetInterval();
timer.Start();
}
private double GetInterval()
{
DateTime now = DateTime.Now;
return ((60 - now.Second) * 1000 - now.Millisecond);
}
It won't.
DateTime.Now uses the system clock as the reference timer, so your timer will always stay in sync with it, modulus the few milliseconds of system clock resolution.
I don't see how it can wander off, everytime the timer ticks, it determines how long it is to the next exact minute and sets the interval accordingly. In theory it is actually quite ingenious, because I timer by itself would wander off. The only way to know for sure would be to test it of course, so as long as your UI doesn't freeze for more then 60 seconds, (maybe 50s to play it safe) there won't be a problem. Keep in mind that laptops will often go to sleep when left for a time, or the lid is closed, this will cause a glitch.
Depending on what you are attemping to do though, why not just use the system time, to send an event everytime the minute changes?
The big picture looks fine, GetInterval will always return a positive value, and so on. I only see a few caveats:
If standby/resume happens then you may have one run at a non-round time
If timer_Elapsed takes more than a minute to complete then you will miss a beat
If the system is so overloaded that timer_Elapsed is scheduled 40/50 seconds in delay AND timer_Elapsed takes more than 60 - delay seconds, you will miss a beat
Your code won't drift, but there will (inevitably) be jitter as Timer callbacks are rarely bang on the requested interval.
The only potential problem I can see with this code is if the ThreadPool were under such strain that your timer callback was not dequeued and executed within a minute interval, resulting in a skipped minute.
This seems somewhat unlikely, but not completely beyond the realms of possibility.