18

I have a windows service written in c#. It has a timer inside, which fires some functions on a regular basis. So the skeleton of my service:

public partial class ArchiveService : ServiceBase
{
    Timer tickTack;
    int interval = 10;
    ...
 
    protected override void OnStart(string[] args)
    {
        tickTack = new Timer(1000 * interval);

        tickTack.Elapsed += new ElapsedEventHandler(tickTack_Elapsed);
        tickTack.Start();
    }

    protected override void OnStop()
    {            
        tickTack.Stop();
    }    
    
    private void tickTack_Elapsed(object sender, ElapsedEventArgs e)
    {
        ...
    }
}

It works for some time (like 10-15 days) then it stops. I mean the service shows as running, but it does not do anything. I make some logging and the problem can be the timer, because after the interval it does not call the tickTack_Elapsed function.

I was thinking about rewrite it without a timer, using an endless loop, which stops the processing for the amount of time I set up. This is also not an elegant solution and I think it can have some side effects regarding memory.

The Timer is used from the System.Timers namespace, the environment is Windows 2003. I used this approach in two different services on different servers, but both is producing this behavior (this is why I thought that it is somehow connected to my code or the framework itself).

Does somebody experienced this behavior? What can be wrong?


Edit:

I edited both services. One got a nice try-catch everywhere and more logging. The second got a timer-recreation on a regular basis. None of them stopped since them, so if this situation remains for another week, I will close this question. Thank you for everyone so far.


Edit:

I close this question because nothing happened. I mean I made some changes, but those changes are not really relevant in this matter and both services are running without any problem since then. Please mark it as "Closed for not relevant anymore".

Community
  • 1
  • 1
Biri
  • 7,101
  • 7
  • 38
  • 52
  • don't close the question, because others may find the information useful; accept an answer instead – Steven A. Lowe May 12 '10 at 18:45
  • Is there anything in the event log after the timer stops running? – brien Dec 29 '08 at 14:00
  • Nothing at all. I can catch the tickTack_Elapsed function, but it is not called anymore. So the log shows that from starting the service I got events every 10 minutes but after a while it just stops without any error message or anything else. Can I log somehow more details? – Biri Dec 29 '08 at 14:05

7 Answers7

18

unhandled exceptions in timers are swallowed, and they silently kill the timer

wrap the body of your timer code in a try-catch block

Steven A. Lowe
  • 60,273
  • 18
  • 132
  • 202
  • from my experience this problem is pretty much always due to an unhandled exception of the timer elasped delegate thread, ie "what Steven said!" – RhysC Feb 09 '10 at 07:25
  • That seems like terrible default behavior, but I've seen this before too. – SqlRyan May 12 '10 at 15:30
  • I cannot believe this is still the case. I have been hitting my head against a wall trying to figure out why my program was stopping suddenly with no message though I had a tremendous amount of log writing. – spinon May 21 '11 at 21:59
  • 2
    @spinon: one of my pet .net peeves - this has been a design flaw since .net 1.0, yet it remains unfixed even after 12 years! – Steven A. Lowe May 21 '11 at 23:06
  • @Steven Agree completely. It is definitely on my list as well. I know I have been seeing this happen before. But I didn't assume that a swallowed exception was the case. – spinon May 22 '11 at 04:20
  • 1
    @Giorgi: yes - otherwise any exceptions in that method (executed on timer-tick) will just silently kill the timer – Steven A. Lowe May 08 '15 at 19:01
5

I have seen this before with both timer, and looped services. Usually the case is that an exception is caught that stops the timer or looping thread, but does not restart it as part of the exception recovery.

To your other points... I dont think that there is anything "elegant" about the timer. For me its more straight forward to see a looping operation in code than timer methods. But Elegance is subjective.

Memory issue? Not if you write it properly. Maybe a processor burden if your Thread.Sleep() isn't set right.

StingyJack
  • 19,041
  • 10
  • 63
  • 122
  • My last idea was that I will connect to the service with VS to debug it. Hopefully I could get the exception whereever it happens. I will also rewrite one of them to a loop. It worth a try. – Biri Dec 29 '08 at 14:12
  • You may want to have a loop that periodically checks the timer to see if its running, or to check the other loop. I use this to automatically restart a stopped timer or loop thread. – StingyJack Dec 29 '08 at 14:18
4

http://support.microsoft.com/kb/842793

This is a known bug that has resurfaced in the Framework more than once.

The best known work-around: don't use timers. I've rendered this bug ineffective by doing a silly "while (true)" loop.

Your mileage may vary, so verify with your combination of OS/Framework bits.

jro
  • 7,372
  • 2
  • 23
  • 36
  • Sorry, I forgot to mention that this is a .NET 2.0 application. But I also don't stop and restart the timer, however there are some points to consider (like using System.Threading instead of System.Timers). I add to my list to try, thanks. – Biri Dec 30 '08 at 09:09
  • I had the same effect as you -- I never stopped/restarted the timer, either. Nonetheless, through detailed logging I was able to ascertain that the timer simply stopped firing events. – jro Dec 30 '08 at 16:14
3

Interesting issue. If it is truly just time related (i.e. not an exception), then I wonder if you can simply periodically recycle the timer - i.e.

private void tickTack_Elapsed(object sender, ElapsedEventArgs e)
{
    CheckForRecycle();
    // ... actual code
}

private void CheckForRecycle()
{
    lock(someLock) {
        if(++tickCount > MAX_TICKS) {
            tickCount = 0;
            tickTack.Stop();
            // re-create timer
            tickTack = new Timer(...);
            tickTack.Elapsed += ...
            tickTack.Start();
        }
    }
}

You could probably merge chunks of this with the OnStart / OnStop etc to reduce duplication.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
3

Like many respondents have pointed out exceptions are swallowed by timer. In my windows services I use System.Threading.Timer. It has Change(...) method which allows you to start/stop that timer. Possible place for exception could be reentrancy problem - in case when tickTack_Elapsed executes longer than timer period. Usually I write timer loop like this:

    void TimeLoop(object arg)
    {
        stopTimer();

        //Do some stuff

        startTimer();
    }

You could also lock(...) your main loop to protect against reentrancy.

Nickolodeon
  • 2,848
  • 3
  • 23
  • 38
0

Have you checked the error logs? Maybe you run out of timers somehow. Maybe you can create just one timer when you initialize the ArchiveService and skip the OnStart stuff.

PEZ
  • 16,821
  • 7
  • 45
  • 66
  • The timer is created only once. The OnStart is running only when I start the service itself, not every time it would like to do something. – Biri Dec 29 '08 at 14:08
0

I have made exactly the same as you in a few projects but have not had the problem.

Do you have code in the tickTac_Elapsed that can be causing this? Like a loop that never ends or some error that stops the timer, using threads and waiting for ending of those and so on?

Stefan
  • 11,423
  • 8
  • 50
  • 75
  • Unfortunately no. The tickTack_Elapsed is working right, I log when it starts and ends. Every time I see a start-stop event pair before it stops responding. Furhermore I also check the running state in there, so it cannot run over to a previously started instance. – Biri Dec 29 '08 at 14:10