vldmrrdjcc
vldmrrdjcc

Reputation: 2132

Code for executing method every day at specific time C# (Windows Service) failed

I had this code to execute method of windows service every day at 5am:

EDIT:

MyService ws = new MyService ();

protected override void OnStart(string[] args)
{
    if (serviceHost != null)
    {
        serviceHost.Close();
    }

    serviceHost = new ServiceHost(typeof(MyService));

    serviceHost.Open();
    double TimeOfExecution = 5;

    DateTime now = DateTime.Now;
    DateTime today5am = now.Date.AddHours(TimeOfExecution);
    DateTime next5am = now <= today5am ? today5am : today5am.AddDays(1);

    System.Threading.TimerCallback callback = new System.Threading.TimerCallback(ws.MethodToExecute());

    var timer1 = new System.Threading.Timer(callback, null, next5am - DateTime.Now, TimeSpan.FromHours(24));

 }

I expected the Service to execute at next 5 o'clock, and every 24 hours after that.

Method MethodToExecute() did get executed at 5 o'clock (or some other specified time) that day, but next day it failed to execute. Also, it seems that it does not matter if I executed it or not for the first time, but it seems like service goes to sleep after some time and doesn't execute, so if 5 o'clock arrives not at current day, but next day, it will fail to execute.

Does anyone have an idea what could be wrong?

Upvotes: 6

Views: 19826

Answers (4)

Inrego
Inrego

Reputation: 1533

Another option could be telling the GarbageCollector to keep the local variable alive:

GC.KeepAlive(timer1);

Upvotes: 0

Hans Passant
Hans Passant

Reputation: 942255

var timer1 = new System.Threading.Timer(...);

Timers are tricky objects. They are subject to garbage collection, just like any .NET objects, when they are no longer referenced. The syntax of this statement is enough to know when that happens, your usage of var shows that "timer1" is a local variable of a method. In other words, there is no reference left to that Timer object you created after your method returns.

So what exactly keeps a Timer alive and ticking when there is no reference left? You found out: nothing. Whether your timer will actually tick is a crapshoot. If your program keeps running doing other things then it triggers a gen#0 collection and the timer will disappear. It will never tick. If your program doesn't then it will survive long enough to make it to 5am.

You must store the object reference in a variable that ensures it survives long enough. That should be a static variable.

Or use a System.Timers.Timer. It acts a lot like a System.Threading.Timer but has better survival skills. It is guaranteed to stay alive as long as it has an Elapsed event handler and it is enabled.

Upvotes: 5

ta.speot.is
ta.speot.is

Reputation: 27214

Please read the fine manual:

Note

As long as you are using a Timer, you must keep a reference to it. As with any managed object, a Timer is subject to garbage collection when there are no references to it. The fact that a Timer is still active does not prevent it from being collected.

Keep a reference to it:

MyService ws = new MyService ();

System.Threading.Timer timer;

protected override void OnStart(string[] args)
{
    ...

    if (timer1 != null)
        timer1.Dispose();

    timer1 = new System.Threading.Timer(callback, null,
        next5am - DateTime.Now, TimeSpan.FromHours(24));
 }

Upvotes: 0

Sriram Sakthivel
Sriram Sakthivel

Reputation: 73502

GC will collect your timer since you don't have any references to it after OnStart method.

You're just having it as a local variable. I hope you know local variables are eligible for garbage collection once JIT says that they are no longer used in code.

Fix: Just store the timer in a instance variabe, you're done.

private System.Threading.Timer my5AmTimer = null;

protected override void OnStart(string[] args)
{
    //All other code..

   this.my5AmTimer = new System.Threading.Timer(callback, null, next5am - DateTime.Now, TimeSpan.FromHours(24));
}

Upvotes: 10

Related Questions