Best Timer for using in a Windows service

199,756

Solution 1

Both System.Timers.Timer and System.Threading.Timer will work for services.

The timers you want to avoid are System.Web.UI.Timer and System.Windows.Forms.Timer, which are respectively for ASP applications and WinForms. Using those will cause the service to load an additional assembly which is not really needed for the type of application you are building.

Use System.Timers.Timer like the following example (also, make sure that you use a class level variable to prevent garbage collection, as stated in Tim Robinson's answer):

using System;
using System.Timers;

public class Timer1
{
    private static System.Timers.Timer aTimer;

    public static void Main()
    {
        // Normally, the timer is declared at the class level,
        // so that it stays in scope as long as it is needed.
        // If the timer is declared in a long-running method,  
        // KeepAlive must be used to prevent the JIT compiler 
        // from allowing aggressive garbage collection to occur 
        // before the method ends. (See end of method.)
        //System.Timers.Timer aTimer;

        // Create a timer with a ten second interval.
        aTimer = new System.Timers.Timer(10000);

        // Hook up the Elapsed event for the timer.
        aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);

        // Set the Interval to 2 seconds (2000 milliseconds).
        aTimer.Interval = 2000;
        aTimer.Enabled = true;

        Console.WriteLine("Press the Enter key to exit the program.");
        Console.ReadLine();

        // If the timer is declared in a long-running method, use
        // KeepAlive to prevent garbage collection from occurring
        // before the method ends.
        //GC.KeepAlive(aTimer);
    }

    // Specify what you want to happen when the Elapsed event is 
    // raised.
    private static void OnTimedEvent(object source, ElapsedEventArgs e)
    {
        Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
    }
}

/* This code example produces output similar to the following:

Press the Enter key to exit the program.
The Elapsed event was raised at 5/20/2007 8:42:27 PM
The Elapsed event was raised at 5/20/2007 8:42:29 PM
The Elapsed event was raised at 5/20/2007 8:42:31 PM
...
 */

If you choose System.Threading.Timer, you can use as follows:

using System;
using System.Threading;

class TimerExample
{
    static void Main()
    {
        AutoResetEvent autoEvent     = new AutoResetEvent(false);
        StatusChecker  statusChecker = new StatusChecker(10);

        // Create the delegate that invokes methods for the timer.
        TimerCallback timerDelegate = 
            new TimerCallback(statusChecker.CheckStatus);

        // Create a timer that signals the delegate to invoke 
        // CheckStatus after one second, and every 1/4 second 
        // thereafter.
        Console.WriteLine("{0} Creating timer.\n", 
            DateTime.Now.ToString("h:mm:ss.fff"));
        Timer stateTimer = 
                new Timer(timerDelegate, autoEvent, 1000, 250);

        // When autoEvent signals, change the period to every 
        // 1/2 second.
        autoEvent.WaitOne(5000, false);
        stateTimer.Change(0, 500);
        Console.WriteLine("\nChanging period.\n");

        // When autoEvent signals the second time, dispose of 
        // the timer.
        autoEvent.WaitOne(5000, false);
        stateTimer.Dispose();
        Console.WriteLine("\nDestroying timer.");
    }
}

class StatusChecker
{
    int invokeCount, maxCount;

    public StatusChecker(int count)
    {
        invokeCount  = 0;
        maxCount = count;
    }

    // This method is called by the timer delegate.
    public void CheckStatus(Object stateInfo)
    {
        AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
        Console.WriteLine("{0} Checking status {1,2}.", 
            DateTime.Now.ToString("h:mm:ss.fff"), 
            (++invokeCount).ToString());

        if(invokeCount == maxCount)
        {
            // Reset the counter and signal Main.
            invokeCount  = 0;
            autoEvent.Set();
        }
    }
}

Both examples comes from the MSDN pages.

Solution 2

Don't use a service for this. Create a normal application and create a scheduled task to run it.

This is the commonly held best practice. Jon Galloway agrees with me. Or maybe its the other way around. Either way, the fact is that it is not best practices to create a windows service to perform an intermittent task run off a timer.

"If you're writing a Windows Service that runs a timer, you should re-evaluate your solution."

–Jon Galloway, ASP.NET MVC community program manager, author, part time superhero

Solution 3

Either one should work OK. In fact, System.Threading.Timer uses System.Timers.Timer internally.

Having said that, it's easy to misuse System.Timers.Timer. If you don't store the Timer object in a variable somewhere, then it is liable to be garbage collected. If that happens, your timer will no longer fire. Call the Dispose method to stop the timer, or use the System.Threading.Timer class, which is a slightly nicer wrapper.

What problems have you seen so far?

Solution 4

I agree with previous comment that might be best to consider a different approach. My suggest would be write a console application and use the windows scheduler:

This will:

  • Reduce plumbing code that replicates scheduler behaviour
  • Provide greater flexibility in terms of scheduling behaviour (e.g. only run on weekends) with all scheduling logic abstracted from application code
  • Utilise the command line arguments for parameters without having to setup configuration values in config files etc
  • Far easier to debug/test during development
  • Allow a support user to execute by invoking the console application directly (e.g. useful during support situations)

Solution 5

As already stated both System.Threading.Timer and System.Timers.Timer will work. The big difference between the two is that System.Threading.Timer is a wrapper arround the other one.

System.Threading.Timer will have more exception handling while System.Timers.Timer will swallow all the exceptions.

This gave me big problems in the past so I would always use 'System.Threading.Timer' and still handle your exceptions very well.

Share:
199,756

Related videos on Youtube

shA.t
Author by

shA.t

A beginner of developing. Laugh to world, The world will laugh to you ;). #SOReady2Help!

Updated on June 27, 2020

Comments

  • shA.t
    shA.t almost 4 years

    I need to create some windows service which will execute every N period of time.
    The question is:
    Which timer control should I use: System.Timers.Timer or System.Threading.Timer one? Does it influence on something?

    I am asking because I heard many evidences to non correct work of System.Timers.Timer in windows services.
    Thank you.

  • sfuqua
    sfuqua almost 14 years
    If your service is intended to run all day, then perhaps a service makes sense rather than a scheduled task. Or, having a service might simplify admin and logging for an infrastructure group that is not as savvy as the application team. However, questioning the assumption that a service is required is entirely valid, and these negatively ratings are undeserved. +1 to both.
  • JP Hellemons
    JP Hellemons over 12 years
    But this requires a logged on user? So service is maybe better if it will run 24/7 on a server.
  • M.R.
    M.R. over 11 years
    Windows scheduled task is extremely buggy. Windows services is a lot more reliable..
  • Admin
    Admin over 11 years
    @m.r. Nonsense. Scheduled tasks are a core part of the OS. Please keep your FUD to yourself.
  • M.R.
    M.R. over 11 years
    @will - That has nothing to do with it. Yes, they are - but if you're going to tell me that because they are a core part of the OS that they are rock solid, that would be silly. Yes, windows is such a stable operating system.
  • Admin
    Admin over 11 years
    @M.R.: I'm not an evangelist, I'm a realist. And reality has taught me that scheduled tasks aren't "extremely buggy." It is, in fact, up to you as the person who made that claim to support it. Otherwise, all you are doing is spreading fear, uncertainty and doubt.
  • SpaceCowboy74
    SpaceCowboy74 over 11 years
    I hate to wade into the mire here, but i have to defend M.R. a little bit. I have several critical applications running in my company that are windows console apps. I have used Windows Task Scheduler for running all of them. On at least 5 occasions now, we have had a problem where the Scheduler Service "got confused" somehow. Tasks didn't execute and some were in a strange state. The only solution was a reboot of the server or stop and start of the Scheduler service. Not something I can do without admin rights and not acceptable in a production environment. Just my $0.02.
  • Admin
    Admin over 11 years
    @SpaceCowboy74: So, is that the norm, or just something that happened to you on one particular server?
  • SpaceCowboy74
    SpaceCowboy74 over 11 years
    It's actually happened to me on a few servers (3 so far). Won't say it's the norm though. Just saying sometimes it's not bad to implement your own method of doing something.
  • Nick N.
    Nick N. about 11 years
    What should I use, if the interval to time for, is variable and configurable?
  • Admin
    Admin about 11 years
    @Nick: Depends. If you need, say, a website where people can change the schedule, then a service. Or, if it is configured once per install, or only very rarely, then a scheduled task is fine.
  • Stonetip
    Stonetip almost 11 years
    Just a thought, but what if your service is dependent on scheduling and some uninformed sys admin migrates it to a new server but forgets to migrate scheduled tasks?
  • Stonetip
    Stonetip almost 11 years
    Makes me wonder why a Windows Phone app can only access System.Threading.Timer.
  • Malachi
    Malachi almost 11 years
    windows phones probably have a lighter version of the framework, having all of that extra code to be able to use both methods is probably not needed so it is not included. I think that Nick's answer, gives a better reason for why Windows phones don't have access to System.Timers.Timer because it won't handle the Exceptions thrown to it.
  • Paul Zahra
    Paul Zahra about 10 years
    "A service application is designed to be long running. Therefore, it usually polls or monitors something in the system." msdn.microsoft.com/en-us/library/zt39148a%28v=vs.100%29.aspx
  • John C
    John C about 10 years
    It’s funny that you suggest using another service that uses timers(contradicting ) to run a console app, rather than role your own. Also, scheduled tasks is NOT a core part of the OS, it is just another service that has been introduced into the OS. It was introduced into windows 2000. Services on the other hand IS a core part of the OS. In my many years I've witnessed many times when the Scheduler Service data has gotten corrupt and NO tasks would run, and the only fix was a fresh OS rebuild. The question comes down to if you want to rely on another service to run your app or create your own.
  • Giorgi Moniava
    Giorgi Moniava almost 9 years
    Why do you suggest: GC.KeepAlive(aTimer);, aTimer is instance variable right, so for example if it is instance variable of form, there will always be reference to it as long as there is form, isn't it?