Timer trouble -timer "dies"
-
Hi all. I have a implemented a Window Service which includes a timer. The timer "ticks" every five minutes, and writes an entry to a database plus enters a line into an eventlog. Unfortunatelly this timer does not seem fully reliable as the service occasionally just stop writing to both the database and the eventlog. Sometimes this happens when it has been running for just a few hours, other times when it has been going for several days. Is there a known limitation in timers? Or is there some internal or external event that might cause the timer to stop? Since the timer does not 'die' at the same tick each time it is very hard to try to debug or something. The code snippets below is pretty straight forward, I hope you can follow it and that it may give you some clue as to what is going wrong here. Do you think it would help to implement a second timer that executes say every ten hours, which creates a new instance of the first timer? That of course would leave me at the mercy of the second timer and in the case where an external event causes the first timer to stop it will most certainly also cause the second timer to stop... Thanks /EnkelIk public class MyService : System.ServiceProcess.ServiceBase { private Timer vscTimer=null; public MyService() { // This call is required by the Windows.Forms Component Designer. InitializeComponent(); //Create eventlog if(!System.Diagnostics.EventLog.SourceExists("MyServiceLogSource")) System.Diagnostics.EventLog.CreateEventSource("MyServiceLogSource","MyServiceLog"); eventLog.Source = "MyServiceLogSource"; eventLog.Log="MyServiceLog"; double interval=300000; vscTimer = new Timer(interval); vscTimer.Elapsed += new ElapsedEventHandler( this.ServiceTimer_Tick ); } ... [ Auto generated code for initializing and disposing process ] ... /// /// Set things in motion so your service can do its work. /// protected override void OnStart(string[] args) { //Start timer vscTimer.AutoReset=true; vscTimer.Enabled=true; vscTimer.Start(); } private void ServiceTimer_Tick(object sender, System.Timers.ElapsedEventArgs e) { this.vscTimer.Stop(); eventLog.WriteEntry("Timer event!"); [Write to database] //Tried to do something about the huge memory consumption... GC.Collect(); //Restart timer this.vscTimer.Start(); } }
-
Hi all. I have a implemented a Window Service which includes a timer. The timer "ticks" every five minutes, and writes an entry to a database plus enters a line into an eventlog. Unfortunatelly this timer does not seem fully reliable as the service occasionally just stop writing to both the database and the eventlog. Sometimes this happens when it has been running for just a few hours, other times when it has been going for several days. Is there a known limitation in timers? Or is there some internal or external event that might cause the timer to stop? Since the timer does not 'die' at the same tick each time it is very hard to try to debug or something. The code snippets below is pretty straight forward, I hope you can follow it and that it may give you some clue as to what is going wrong here. Do you think it would help to implement a second timer that executes say every ten hours, which creates a new instance of the first timer? That of course would leave me at the mercy of the second timer and in the case where an external event causes the first timer to stop it will most certainly also cause the second timer to stop... Thanks /EnkelIk public class MyService : System.ServiceProcess.ServiceBase { private Timer vscTimer=null; public MyService() { // This call is required by the Windows.Forms Component Designer. InitializeComponent(); //Create eventlog if(!System.Diagnostics.EventLog.SourceExists("MyServiceLogSource")) System.Diagnostics.EventLog.CreateEventSource("MyServiceLogSource","MyServiceLog"); eventLog.Source = "MyServiceLogSource"; eventLog.Log="MyServiceLog"; double interval=300000; vscTimer = new Timer(interval); vscTimer.Elapsed += new ElapsedEventHandler( this.ServiceTimer_Tick ); } ... [ Auto generated code for initializing and disposing process ] ... /// /// Set things in motion so your service can do its work. /// protected override void OnStart(string[] args) { //Start timer vscTimer.AutoReset=true; vscTimer.Enabled=true; vscTimer.Start(); } private void ServiceTimer_Tick(object sender, System.Timers.ElapsedEventArgs e) { this.vscTimer.Stop(); eventLog.WriteEntry("Timer event!"); [Write to database] //Tried to do something about the huge memory consumption... GC.Collect(); //Restart timer this.vscTimer.Start(); } }
Dear EnkelIk, i have the same broblem with dieing the timers so you should use the timer of threading try System.Threading.Timer this class is beter that the standered one you can create it by using call back function it is good one so try it Mhmoud Rawas ------------ Software Eng.
-
Hi all. I have a implemented a Window Service which includes a timer. The timer "ticks" every five minutes, and writes an entry to a database plus enters a line into an eventlog. Unfortunatelly this timer does not seem fully reliable as the service occasionally just stop writing to both the database and the eventlog. Sometimes this happens when it has been running for just a few hours, other times when it has been going for several days. Is there a known limitation in timers? Or is there some internal or external event that might cause the timer to stop? Since the timer does not 'die' at the same tick each time it is very hard to try to debug or something. The code snippets below is pretty straight forward, I hope you can follow it and that it may give you some clue as to what is going wrong here. Do you think it would help to implement a second timer that executes say every ten hours, which creates a new instance of the first timer? That of course would leave me at the mercy of the second timer and in the case where an external event causes the first timer to stop it will most certainly also cause the second timer to stop... Thanks /EnkelIk public class MyService : System.ServiceProcess.ServiceBase { private Timer vscTimer=null; public MyService() { // This call is required by the Windows.Forms Component Designer. InitializeComponent(); //Create eventlog if(!System.Diagnostics.EventLog.SourceExists("MyServiceLogSource")) System.Diagnostics.EventLog.CreateEventSource("MyServiceLogSource","MyServiceLog"); eventLog.Source = "MyServiceLogSource"; eventLog.Log="MyServiceLog"; double interval=300000; vscTimer = new Timer(interval); vscTimer.Elapsed += new ElapsedEventHandler( this.ServiceTimer_Tick ); } ... [ Auto generated code for initializing and disposing process ] ... /// /// Set things in motion so your service can do its work. /// protected override void OnStart(string[] args) { //Start timer vscTimer.AutoReset=true; vscTimer.Enabled=true; vscTimer.Start(); } private void ServiceTimer_Tick(object sender, System.Timers.ElapsedEventArgs e) { this.vscTimer.Stop(); eventLog.WriteEntry("Timer event!"); [Write to database] //Tried to do something about the huge memory consumption... GC.Collect(); //Restart timer this.vscTimer.Start(); } }
Several things: if you read the documentation for
Start
andStop
, they are exactly the same as passingtrue
andfalse
to theTimer.Enabled
property, respectively. Don't do both because it's a waste of CPU time. Second, it is recommended that you don't useGC.Collect
. Instead, dispose of the objects in your "[Write to database]" block that implementIDisposable
. Finally: exception handling and stopping / starting timers. What's probably happening is that since you're stopping the timer, writing to the event log, and then performing database functions - which can be volatile - and then starting the timer again, if an exception were to be thrown your time would not be started again! Instead, put your database calls in a try-catch and gracefully catch all exceptions, or addthis.vscTimer.Start()
to afinally
block of a try-catch-finally or try-finally (exceptions are still thrown in the latter block, butfinally
is always executed regardless of success. You should also enable auto-logging on the Windows Service by settingServiceBase.AutoLog
to true (of course, your service inheritsServiceBase
, so you can set this property on yourself, too). One more option: don't stop the timer! If you don't stop it, even if the database code throws an exception, the timer will keep running. Besides, lets say all the database code takes 2 seconds and you run this code every 10 minutes. That means that you're shifting time about 4.8 minutes per day! Just let it run, man! :)-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
-
Several things: if you read the documentation for
Start
andStop
, they are exactly the same as passingtrue
andfalse
to theTimer.Enabled
property, respectively. Don't do both because it's a waste of CPU time. Second, it is recommended that you don't useGC.Collect
. Instead, dispose of the objects in your "[Write to database]" block that implementIDisposable
. Finally: exception handling and stopping / starting timers. What's probably happening is that since you're stopping the timer, writing to the event log, and then performing database functions - which can be volatile - and then starting the timer again, if an exception were to be thrown your time would not be started again! Instead, put your database calls in a try-catch and gracefully catch all exceptions, or addthis.vscTimer.Start()
to afinally
block of a try-catch-finally or try-finally (exceptions are still thrown in the latter block, butfinally
is always executed regardless of success. You should also enable auto-logging on the Windows Service by settingServiceBase.AutoLog
to true (of course, your service inheritsServiceBase
, so you can set this property on yourself, too). One more option: don't stop the timer! If you don't stop it, even if the database code throws an exception, the timer will keep running. Besides, lets say all the database code takes 2 seconds and you run this code every 10 minutes. That means that you're shifting time about 4.8 minutes per day! Just let it run, man! :)-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
Heath, I haven't seen the code that causes this problme so I may not be making any sense here. Feel free to use your vast reserves of knowledge to correct me. ;) The .NET timer class uses the .NET built-in thread pool to execute the timer callback function. The .NET built-in thread pool has a maximum of 25 threads as the default limit. If the timer callback function got stuck (with some database operations, for example) for longer than the timer interval (5 minutes in this case), the timer callback function will be invoked by a new thread from the thread pool. If this new thread got stuck again, then another new thread from the thread pool will be used. Anyway, under some conditions, the timer can exaust all 25 threads from the thread pool. I have posted a simple example in a message after my article Creating Your Own Thread Pool In .NET[^] to demonstrate this. If there is no easy way to figure out what caused the timer callback to stuck, then the solution may be not using the .NET timer class at all or restarting the applcation when too many threads are being used to handle the timer event.[
My articles and software tools
-
Heath, I haven't seen the code that causes this problme so I may not be making any sense here. Feel free to use your vast reserves of knowledge to correct me. ;) The .NET timer class uses the .NET built-in thread pool to execute the timer callback function. The .NET built-in thread pool has a maximum of 25 threads as the default limit. If the timer callback function got stuck (with some database operations, for example) for longer than the timer interval (5 minutes in this case), the timer callback function will be invoked by a new thread from the thread pool. If this new thread got stuck again, then another new thread from the thread pool will be used. Anyway, under some conditions, the timer can exaust all 25 threads from the thread pool. I have posted a simple example in a message after my article Creating Your Own Thread Pool In .NET[^] to demonstrate this. If there is no easy way to figure out what caused the timer callback to stuck, then the solution may be not using the .NET timer class at all or restarting the applcation when too many threads are being used to handle the timer event.[
My articles and software tools
Thanks, but I don't think that was his problem. His
Elapsed
handler stopped the timer, ran some database code, then started the timer again after the database code completed. The database code was not wrapped in a try-catch block and if any exceptions where thrown, the timer would not be restarted. Or am I missing your point? BTW, I've read your article and found it very interesting. Good job!-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
-
Thanks, but I don't think that was his problem. His
Elapsed
handler stopped the timer, ran some database code, then started the timer again after the database code completed. The database code was not wrapped in a try-catch block and if any exceptions where thrown, the timer would not be restarted. Or am I missing your point? BTW, I've read your article and found it very interesting. Good job!-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
Heath Stewart wrote: Thanks, but I don't think that was his problem. You are right again. I wasn't reading the code in his post carefully. :-O Thanks.[
My articles and software tools
-
Dear EnkelIk, i have the same broblem with dieing the timers so you should use the timer of threading try System.Threading.Timer this class is beter that the standered one you can create it by using call back function it is good one so try it Mhmoud Rawas ------------ Software Eng.
-
Several things: if you read the documentation for
Start
andStop
, they are exactly the same as passingtrue
andfalse
to theTimer.Enabled
property, respectively. Don't do both because it's a waste of CPU time. Second, it is recommended that you don't useGC.Collect
. Instead, dispose of the objects in your "[Write to database]" block that implementIDisposable
. Finally: exception handling and stopping / starting timers. What's probably happening is that since you're stopping the timer, writing to the event log, and then performing database functions - which can be volatile - and then starting the timer again, if an exception were to be thrown your time would not be started again! Instead, put your database calls in a try-catch and gracefully catch all exceptions, or addthis.vscTimer.Start()
to afinally
block of a try-catch-finally or try-finally (exceptions are still thrown in the latter block, butfinally
is always executed regardless of success. You should also enable auto-logging on the Windows Service by settingServiceBase.AutoLog
to true (of course, your service inheritsServiceBase
, so you can set this property on yourself, too). One more option: don't stop the timer! If you don't stop it, even if the database code throws an exception, the timer will keep running. Besides, lets say all the database code takes 2 seconds and you run this code every 10 minutes. That means that you're shifting time about 4.8 minutes per day! Just let it run, man! :)-----BEGIN GEEK CODE BLOCK----- Version: 3.21 GCS/G/MU d- s: a- C++++ UL@ P++(+++) L+(--) E--- W+++ N++ o+ K? w++++ O- M(+) V? PS-- PE Y++ PGP++ t++@ 5 X+++ R+@ tv+ b(-)>b++ DI++++ D+ G e++>+++ h---* r+++ y+++ -----END GEEK CODE BLOCK-----
Thanks. Using System.Threading.Timer plus improved error handling (try-catch) my service seems much more stable than before. It's quite true that I have no need to stop and start the timer (even when not using the Threading timer), don't know why I got that idea. I have also with interest read Xiangyang Liu's article but I don't think that will be any serious and frequent problem in my case. Again, THANKS! /EnkelIk