.NET Forum / .NET Framework / New Users / October 2006
System.Timers.Timer Issue
|
|
Thread rating:  |
Ethan Selzer - 05 Jan 2006 23:57 GMT Hi,
I have an instance of the System.Timers.Timer class (V1.1) running in a Windows Service. When the Elapsed event fires the Timer.Interval property is set to 24 hours ahead, which results in the Elapsed event firing once a day. Twice in the last 45 days the Elapsed event fired repeatedly until it was terminated manually. The Timer.Interval is recorded in the Application Event Log on each firing of the Elapsed event and it is correctly set to the following day. Any recommendations on how I might proceed with correcting this issue are greatly appreciated.
Thanks, Ethan
Kevin Spencer - 06 Jan 2006 14:34 GMT Are you saying that you are resetting the Interval each time the timer fires? If so, why? If not, can you clarify?
 Signature HTH,
Kevin Spencer Microsoft MVP .Net Developer You can lead a fish to a bicycle, but it takes a very long time, and the bicycle has to *want* to change.
> Hi, > [quoted text clipped - 12 lines] > Thanks, > Ethan Ethan Selzer - 06 Jan 2006 18:20 GMT Yes, that is correct. The reason is that I want the timer to fire each day at a specific time that is configured in ap.config. So if the time is set to 2:00 PM in ap.config then the current DateTime is subtracted from the DateTime of 2:00 PM the following day and the Interval property is set to the resulting TimeSpan.
Ethan
> Are you saying that you are resetting the Interval each time the timer > fires? If so, why? If not, can you clarify? [quoted text clipped - 15 lines] > > Thanks, > > Ethan Hemant Mehta - 19 Sep 2006 07:49 GMT Hi Ethan,
Did you find a solution to this. I have run into the same problem. Thought the timer interval it set to 24 hrs after 45 days the timer started firing repeatedly until we stopped the service manually.
Thanks in advance Hemant
Schmechel - 02 Oct 2006 20:24 GMT We have the same issue - right down to the timer being set for 24 hours!
I have seen posts about using the Threading.Timer in place of System.Timer, but they usually have to do with the timer not firing.
I have seen this "constant fire" state in our windows service 3 times in the field. Each time it cripples the system and requires technical service intervention.
I really want to get to the bottom of this issue. Do we need to start a new thread so that someone from Microsoft sees this?
> Hi Ethan, > [quoted text clipped - 6 lines] > > *** Sent via Developersdex http://www.developersdex.com *** William Stacey [C# MVP] - 02 Oct 2006 22:23 GMT Does System.Threading.Timer show this issue also?
 Signature William Stacey [C# MVP]
| We have the same issue - right down to the timer being set for 24 hours! | [quoted text clipped - 18 lines] | > | > *** Sent via Developersdex http://www.developersdex.com *** Schmechel - 03 Oct 2006 14:19 GMT The problem is that I can not reproduce the state effectively in-house. I have thought about switching to System.Threading.Timer, but I do not want to trade one issue for another.
It seems that System.Threading.Timer has issues with failing to fire. See: http://support.microsoft.com/?id=900822
It may be that this other problem would be easier to "live with" than the event-flood" I have experienced, but I would prefer to find a true fix for this problem rather than just settling.
---------------
> Does System.Threading.Timer show this issue also? William Stacey [C# MVP] - 03 Oct 2006 16:25 GMT Seems to effect 1.1sp1. If you on 2.0, I might just try it and see.
 Signature William Stacey [C# MVP]
| The problem is that I can not reproduce the state effectively in-house. | I have thought about switching to System.Threading.Timer, but I do not want [quoted text clipped - 11 lines] | | > Does System.Threading.Timer show this issue also? Schmechel - 03 Oct 2006 17:30 GMT > Seems to effect 1.1sp1. If you on 2.0, I might just try it and see. > [quoted text clipped - 14 lines] > | > | > Does System.Threading.Timer show this issue also? Schmechel - 03 Oct 2006 18:50 GMT Sorry for the previous botched post.
We have not yet switched to 2.0. I desperately need a patch for this problem. Moving to 2.0 would require regression testing the rest of our software before I could issue a patch.
What I need is someone with intimate knowledge of System.Timers.Timer and Windows Services (and their inherent multi-threading) to try to determine how this problem could happen.
Even if someone could provide a way to reproduce the problem on demand, I would be in much better shape. At least I could test my patch to see if it is effective or justify refactoring the timers in our service to another type based on some empirical evidence.
Also, if it is reproducible, I could file a bug report with Microsoft. If this is a problem with the System.Timers.Timer class it should be fixed for all .NET users. If the class is correct, but my usage is a misapplication of the System.Timers.Timer class, then something should be published to warn developers. Based on the documentation I have seen, this code should work for our purposes.
Thank you for any help you can provide.
> Seems to effect 1.1sp1. If you on 2.0, I might just try it and see. Peter Bromley - 04 Oct 2006 06:59 GMT > What I need is someone with intimate knowledge of System.Timers.Timer and > Windows Services (and their inherent multi-threading) to try to determine how > this problem could happen. I dont know about "Intimate" but a little reflection shows that System.Timers.Timer uses System.Threading.Timer internally.
Also, both classes make heavy use of uint32 variables even though they appear to provide int64 and double constructors/setters.
Unfortunately, Threading.Timers goes off to native routines so I can't tell what the actual timer implementation is.
I would suggest that there is a int32 or uint32 overflow going on (especially since you mentioned >45 days) so some internal variable wraps and causes the always-on firing condition.
As a workaround, why don't you dispose the timer every time it fires and create a new one, since it fires only once every 24 hours. Would the minimal amount of drift this causes be a problem?
Good luck with a proper solution.
Schmechel - 04 Oct 2006 16:27 GMT Thank you Peter. I will definitely take your advice about disposing and recreating the timers.
Another interesting observation about this issue:
There are actually 4 timers used by this service. Their timespans can be changed individually, but they are normally run at their defaults where three fire once per day and one fires once per hour. They all start at the same time and run for the life of the service.
When we have had problems, the three daily timers are all firing continuously. The hourly timer continues to function at once per hour.
All the timers have experienced the same overall run time. There must be some math going on internally that involves the timer interval and some overall increasing counter.
I'm going to set up a test service to try to replicate the issue. I will try to adjust the .NET tick-count to get to happen in less than 45 days, but it might end up taking a while to duplicate.
Is there any way to know if the timer class uses the tick-count internally? Does .NET reference any Win32 classes to implement the timers? Any further advice on how to speed up the testing process would be appreciated.
Thanks again. -----------
> I dont know about "Intimate" but a little reflection shows that > System.Timers.Timer uses System.Threading.Timer internally. [quoted text clipped - 14 lines] > > Good luck with a proper solution. Kevin Spencer - 04 Oct 2006 21:40 GMT Hi Schmechel,
What I do in my services is dispose and re-instantiate the timers when they elapse. Of course, they only elapse every few minutes, and at that rate it doesn't really affect performance. I I disposed of them every so many milliseconds, I would look for a less-frequent solution.
 Signature HTH,
Kevin Spencer Microsoft MVP Software Composer http://unclechutney.blogspot.com
If the Truth hurts, wear it.
> Thank you Peter. I will definitely take your advice about disposing and > recreating the timers. <snip>
> I'm going to set up a test service to try to replicate the issue. I will > try to adjust the .NET tick-count to get to happen in less than 45 days, [quoted text clipped - 8 lines] > > Thanks again. William Stacey [C# MVP] - 05 Oct 2006 07:00 GMT You could also opt for a cron-type solution. Have a thread that sleeps for a minute (or until next job milliseconds) and wakes up and checks the date on the next job to run, if it >= DateTime.Now, then run job on TP thread. Sleep again for a minute (or until next job). This way, you have no timers to worry about not firing or disposing them, etc. It does take a thread, but that should not be an issue as you only need one. You also know if you have an issue as you catch error/exit of the thread.
 Signature William Stacey [C# MVP]
| Hi Schmechel, | [quoted text clipped - 18 lines] | > | > Thanks again. Schmechel - 05 Oct 2006 18:46 GMT We definitely will be moving to a better solution for handling these periodic events in the next version.
I did, however, find the true root of the problem and I can now reproduce it.
The base problem is with the set method of the Timer.Interval property.
Background: The Interval property is typed as double but has a check that will throw an ArgumentException if the value is less than or equal to zero. You can set the interval all the way up to Double.MaxValue without error. However, when you call the Timer.Start() method, it will throw an ArgumentOutOfRangeException if the Interval is greater than or equal Int32.MaxValue (2,147,483,647) or less than or equal to zero. The developers are obviously trying to protect some internal variable from a too-large value. (Why this class is designed this way is another mystery. Perhaps some backwards-compatibility requirement?)
The problem surfaces when you change the Timer’s interval property after the timer is running. Internally, some math is done which involves the Environment.TickCount (probably trying to account for the fact that the interval value may be changed part way through the current interval). Environment.TickCount is a Uint32 variable (max value 4,294,967,295 or 49.71 days when representing milliseconds).
If the current value of the TickCount, when combined with the new Interval value exceeds Uint32.MaxValue, the timer will begin firing continuously until the overflow ends. This requires either changing the Interval again or waiting for the TickCount to reset.
To summarize, if your system has been running for less than ~25 days, there is no way you can experience a problem. Over the next ~25 days, the safe maximum interval set limit decreases to zero. If you exceed the limit, the timer will fire continuously until the end of the TickCount cycle. Because of the time relation, the larger the interval – the longer it will misbehave. The maximum time that it can misbehave is the interval you specified.
If the timer’s event handler updates the interval (as was my case) it will often be less than the full interval time because the problem will not appear until the event and subsequent setting of the interval actually occurs. (If the Timer’s start time would be random with respect to the host computers start time, the error time would tend towards an average of Interval/2.) This corresponds to my observation of field failures, which occurred, on average, within 12 hours of the system uptime reaching 50 days of uptime. (My hourly timer would have failed also approximately 11.5 hours after the daily timers had the service not been restarted.)
Limitations: If you are not updating the interval, and instead using the AutoReset feature, you will never see this problem. If you set the Interval to a value that, when combined with TickCount, would cause an overflow, then subsequently call the timer’s Start() method, you will not experience a problem.
I now know how to patch my code until I can redesign the next official version. I do want to file this bug with Microsoft. Does anyone know the best way to do that?
If you want to investigate this problem yourself you will probably find the “Adjust Tick Count” utility useful as it avoids a lot of waiting. http://www.ysgyfarnog.co.uk/utilities/adjusttickcount/
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|