Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 415
vldmrrdjcc Avatar asked Nov 29 '13 09:11

vldmrrdjcc


2 Answers

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));
}
like image 88
Sriram Sakthivel Avatar answered Sep 19 '22 21:09

Sriram Sakthivel


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.

like image 39
Hans Passant Avatar answered Sep 20 '22 21:09

Hans Passant