I created a windows service with a timer in it, where I need to set set the interval after each Elapsed timer event. For example, I'd like it to fire on the hour every hour.
In Program.cs:
namespace LabelLoaderService
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
///
static void Main()
{
#if (!DEBUG)
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new LabelLoader()
};
ServiceBase.Run(ServicesToRun);
#else
LabelLoader ll = new LabelLoader();
ll.Start();
#endif
}
}
}
In LabelLoader.cs:
namespace LabelLoaderService
{
public partial class LabelLoader : ServiceBase
{
System.Timers.Timer timer = new System.Timers.Timer();
public LabelLoader()
{
InitializeComponent();
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
}
protected override void OnStart(string[] args)
{
SetTimer();
}
public void Start()
{
// Debug Startup
SetTimer();
}
public void SetTimer()
{
DateTime nextRunTime = GetNextRunTime();
var ts = nextRunTime - DateTime.Now;
timer.Interval = ts.TotalMilliseconds;
timer.AutoReset = true; // tried both true & false
timer.Enabled = true;
GC.KeepAlive(timer); // test - no effect with/without this line
}
void timer_Elapsed(object source, ElapsedEventArgs e)
{
timer.Enabled = false;
// do some work here
SetTimer();
}
If I installutil this onto my local machine, it correctly determines the next run time and executes. But it doesnt run anytime after that. If I restart the service it runs the next scheduled time and then nothing again. Is there an issue calling SetTimer() at the end of my processing to reset the Interval and set timer.Start()?
use System.Threading.Timer instead - in my experience it is more suited for server-like use...
EDIT - as per comment some code/hints:
the following is a very basic way to avoid reentry (should work ok in this specific case) - better would be some lock/Mutex or similar
make nextRunTime an instance field
create/start your time with for example
// first the TimerCallback, second the parameter (see AnyParam), then the time to start the first run, then the interval for the rest of the runs
timer = new System.Threading.Timer(new TimerCallback(this.MyTimerHandler), null, 60000, 30000);
create your timer handler similar to
void MyTimerHandler (object AnyParam)
{
if ( nextRunTime > DateTime.Now)
return;
nextRunTime = DateTime.MaxValue;
// Do your stuff here
// when finished do
nextRunTime = GetNextRunTime();
}
Related
I've got this code in a Windows Service:
public void ConfigureService()
{
//timer = new Timer { Interval = 600000 };
timer = new Timer { Interval = 10000 };
// 10 minutes; 1 second while testing
timer.Elapsed += timer_Tick;
timer.Enabled = true;
RoboRprtrLib.WriteToLog("RoboRprtrService has started");
}
private void timer_Tick(object sender, ElapsedEventArgs eeargs)
{
timer.Elapsed -= timer_Tick;
try
{
RoboRprtrLib.WriteToLog("Timer has ticked");
RoboRprtrLib.GenerateAndEmailDueReports();
}
finally
{
timer.Elapsed += timer_Tick;
}
}
ConfigureService() is called from Program.cs:
static void Main()
{
// got this idea ("How to Debug or Test your Windows Service Without Installing it...") from http://www.codeproject.com/Tips/261190/How-to-Debug-or-Test-your-Windows-Service-Without
#if(!DEBUG)
var ServicesToRun = new ServiceBase[]
{
new RoboRprtrService()
};
ServiceBase.Run(ServicesToRun);
#else
var rrs = new RoboRprtrService();
rrs.ConfigureService();
#endif
}
I have a breakpoint in ConfigureService() on this line:
timer = new Timer { Interval = 10000 };
It is reached; I can step through the entire ConfigureService() method.
I have a breakpoint in the Elapsed/Tick event on the first line:
timer.Elapsed -= timer_Tick;
...and it is never reached.
Why not? Isn't the timer set to trip after 10 seconds, at which point the Tick event handler should be called?
UPDATE
This is the entire code for the class deriving from ServiceBase:
public partial class RoboRprtrService : ServiceBase
{
private Timer timer;
public RoboRprtrService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
ConfigureService();
}
public void ConfigureService()
{
//timer = new Timer { Interval = 600000 };
timer = new Timer { Interval = 50000 };
// 10 minutes; 50 seconds while testing
timer.Elapsed += timer_Tick;
timer.Enabled = true;
RoboRprtrLib.WriteToLog("RoboRprtrService has started");
}
private void timer_Tick(object sender, ElapsedEventArgs eeargs)
{
timer.Elapsed -= timer_Tick;
try
{
RoboRprtrLib.WriteToLog("Timer has ticked");
RoboRprtrLib.GenerateAndEmailDueReports();
}
finally
{
timer.Elapsed += timer_Tick;
}
}
protected override void OnStop()
{
timer.Enabled = false;
RoboRprtrLib.WriteToLog("RoboRprtrService has stopped");
}
}
UPDATE 2
It seems odd to me, but if I add this line:
RoboRprtrLib.GenerateAndEmailDueReports();
...to the end of the ConfigureService() method, the timer is eventually tripped.
UPDATE 3
More oddities: I was getting err msgs about needing to add the STAThread attribute (and a method was being called that shouldn't have been, which caused it to fail and the service to crash). So I decorated Main() in Program.cs with "[STAThread]" and now it works as it should.
The timer tripped several times during the operation, but I have code to exit if processing is occurring. When the called method completed, the IDE "flashed" as if to say, "Poof! I'm outta here!"
So my Program.cs code is now:
[STAThread]
static void Main()
{
#if(!DEBUG)
var ServicesToRun = new ServiceBase[]
{
new RoboRprtrService()
};
ServiceBase.Run(ServicesToRun);
#else
var rrs = new RoboRprtrService();
rrs.ConfigureService();
Console.ReadLine();
#endif
}
...and the most pertinent code in the class that derives from ServiceBase is:
public void ConfigureService()
{
//timer = new Timer { Interval = 600000 };
timer = new Timer { Interval = 50000 };
// 10 minutes; 50 seconds while testing
timer.Elapsed += timer_Tick;
timer.Enabled = true;
RoboRprtrLib.WriteToLog("RoboRprtrService has started");
operationIsRunning = true;
RoboRprtrLib.GenerateAndEmailDueReports();
operationIsRunning = false;
}
private void timer_Tick(object sender, ElapsedEventArgs eeargs)
{
if (operationIsRunning) return;
operationIsRunning = true;
. . .
The "if (operationIsRunning) return;" breakpoint in the tick handler was reached three times during my last run while GenerateAndEmailDueReports() was executing, and each time it, as designed, returned.
As Hans Passant said in comments, in debug mode you code will terminate immediately after calling ConfigureService, so there is no time for the timer to be executed.
In release mode ServiceBase.Run blocks the thread until the service has finished, but this doesn't happen in debug version.
EDIT:
Actually I tried with Console.ReadLine() and did not stop, apparently standard input is redirected, just try to keep the process running, with an infinite loop or something.
Like this:
static void Main()
{
// got this idea ("How to Debug or Test your Windows Service Without Installing it...") from http://www.codeproject.com/Tips/261190/How-to-Debug-or-Test-your-Windows-Service-Without
#if(!DEBUG)
var ServicesToRun = new ServiceBase[]
{
new RoboRprtrService()
};
ServiceBase.Run(ServicesToRun);
#else
var rrs = new RoboRprtrService();
rrs.ConfigureService();
while (true)
Thread.Sleep(100);
#endif
}
I have tried to run the service every 1 minute and i have succeeded in doing so but the problem is its starting every minute regardless of the completion of the program. I have written it like this
private Timer _timer;
private DateTime _lastRun = DateTime.Now.AddDays(-1);
public SpotlessService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
_timer = new Timer(1 * 60 * 1000); // every 1 hour
_timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
_timer.Start();
}
public void Start()
{
OnStart(new string[0]);
}
void timer_Elapsed(object sender, EventArgs e)
{
Util.LogError("Started at" + DateTime.Now + "");
FileDownload objdwn = new FileDownload();
}
I have hosted it as a service and FileDownload class constructor will download some files from server and will copy the data into the database which will take like 10-15 minutes. So what i need to do is i should stop the timer till these fifteen minutes and the service should start again and should wait for the next minute and do the same thing. is this possible or should i just increase the timer value to greater extent
Stop() the timer at the beginning of the Elapse event and Start() the timer at the end. Also ensure your timer object does not get garbage collected.
private Timer _timer;
private DateTime _lastRun = DateTime.Now.AddDays(-1);
public SpotlessService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
_timer = new Timer(1 * 60 * 1000); // every 1 minute
_timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
_timer.Start();
}
public void Start()
{
OnStart(new string[0]);
}
void timer_Elapsed(object sender, EventArgs e)
{
_timer.Stop();
Util.LogError("Started at" + DateTime.Now + "");
FileDownload objdwn = new FileDownload();
_timer.Start()
}
My suggestion is to use Task to perform download and call the main method again as soon as it is finished.
public void mainMethod()
{
Thread.Sleep(60000);
doDownload();
}
public void doDownload()
{
Task.Factory.StartNew(() => {
// Background download
}).ContinueWith(task => mainMethod());
}
This will allow you to perform any additional operations in the main thread if needed while the download is in progress.
OR
You can just stop the timer and run again as soon as the download is done
void timer_Elapsed(object sender, EventArgs e)
{
_timer.Stop();
Util.LogError("Started at" + DateTime.Now + "");
FileDownload objdwn = new FileDownload();
_timer.Start();
}
I'm using a System.Timers.Timer in my application. Every second I run a function which does some job. The thing is, this function can block for some little time (it reads then processes a large file from disk). I want to start that function only if its previous "execution instance" has completed. I thought I could achieve this with a Mutex:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Timers;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static Mutex TimerMut = new Mutex(false);
public static void Main()
{
Thread TT = new Thread(new ThreadStart(delegate()
{
System.Timers.Timer oTimer = new System.Timers.Timer();
oTimer.Elapsed += new ElapsedEventHandler(Handler);
oTimer.Interval = 1000;
oTimer.Enabled = true;
}));
TT.Start();
Console.Read();
}
private static void Handler(object oSource,
ElapsedEventArgs oElapsedEventArgs)
{
TimerMut.WaitOne();
Console.WriteLine("foo");
Thread.Sleep(500); //simulate some work
Console.WriteLine("bar");
TimerMut.ReleaseMutex();
}
}
}
That doesn't work, "foos" still appear every second. How can I achieve this?
EDIT: You're right, it makes no sense to start a new thread to handle this. I thought only System.Threading.Timer is launched in a separate thread.
I'm not sure why you are using a new thread to start the timer, since timers run on their own thread, but here's a method that works. Simply turn the timer off until you are done with the current interval.
static System.Timers.Timer oTimer
public static void Main()
{
oTimer = new System.Timers.Timer();
oTimer.Elapsed += new ElapsedEventHandler(Handler);
oTimer.Interval = 1000;
oTimer.Enabled = true;
}
private void Handler(object oSource, ElapsedEventArgs oElapsedEventArgs)
{
oTimer.Enabled = false;
Console.WriteLine("foo");
Thread.Sleep(5000); //simulate some work
Console.WriteLine("bar");
oTimer.Enabled = true;
}
If you want to skip the tick if another is already working you can do this.
private readonly object padlock = new object();
private void SomeMethod()
{
if(!Monitor.TryEnter(padlock))
return;
try
{
//Do heavy work
}
finally
{
Monitor.Exit(padlock);
}
}
Easiest way I know of to do this kind of thing:
internal static volatile bool isRunning;
public static void Main()
{
Thread TT = new Thread(new ThreadStart(delegate()
{
System.Timers.Timer oTimer = new System.Timers.Timer();
oTimer.Elapsed += new ElapsedEventHandler(Handler);
oTimer.Interval = 1000;
oTimer.Enabled = true;
}));
TT.Start();
}
private void Handler(object oSource,
ElapsedEventArgs oElapsedEventArgs)
{
if(isRunning) return;
isRunning = true;
try
{
Console.WriteLine("foo");
Thread.Sleep(500); //simulate some work
Console.WriteLine("bar");
}
finally { isRunning = false; }
}
The handler still runs, but the very first thing it does is make sure that another handler isn't running, and if one is, it stops immediately.
For timers executing handlers more quickly (like 3-4 times a second), this has the possibility to race; two threads could proceed past the guard clause before one of them sets the bit. You can avoid this with a couple of lock statements, similar to a Mutex or Monitor:
static object syncObj = new object();
private void Handler(object oSource,
ElapsedEventArgs oElapsedEventArgs)
{
lock(syncObj)
{
if(isRunning) return;
isRunning = true;
}
try
{
Console.WriteLine("foo");
Thread.Sleep(500); //simulate some work
Console.WriteLine("bar");
}
finally { lock(syncObj) { isRunning = false; } }
}
This will ensure that only one thread can ever be examining or modifying isRunning, and as isRunning is marked volatile, the CLR won't cache its value as part of each thread's state for performance; each thread has to look at exactly the same memory location to examine or change the value.
You can follow the following pattern to skip doing the indicated work if another invocation of this method is still running:
private int isWorking = 0;
public void Foo()
{
if (Interlocked.Exchange(ref isWorking, 1) == 0)
{
try
{
//Do work
}
finally
{
Interlocked.Exchange(ref isWorking, 0);
}
}
}
The approach that you were using with a Mutex will result in addition ticks waiting for earlier ticks to finish, not skipping invocations when another is still running, which is what you said you wanted. (When dealing with timers like this its common to want to skip such ticks, not wait. If your tick handlers regularly take too long you end up with a giant queue of waiting handlers.)
this time I come to you guys asking for help with Timers (System.Timers to be specific, I believe)
I need to make a timer that runs a function every second, so far this is what I've got:
public class Game1 : Microsoft.Xna.Framework.Game
{
Timer CooldownTracker;
protected override void LoadContent()
{
CooldownTracker = new Timer();
CooldownTracker.Interval = 1000;
CooldownTracker.Start();
}
private void DecreaseCooldown(List<Brick> bricks)
{
foreach (Brick brick in bricks)
{
if (brick.Cooldown == 0)
brick.Cooldown = 2;
else
brick.Cooldown--;
}
}
}
...How do I make the timer run the DecreasedCooldown(List bricks) function? I've tried with Timer.Elapsed but I get nothing, I can't pass down the arguments that way. Any ideas?
Thanks!
You need to attach a Timer Elapsed event like:
CooldownTracker = new Timer();
CooldownTracker.Elapsed += CooldownTracker_Elapsed; //HERE
CooldownTracker.Interval = 1000;
CooldownTracker.Start();
and then the event:
void CooldownTracker_Elapsed(object sender, ElapsedEventArgs e)
{
DecreaseCooldown(yourList);
}
You can use Thread if you want. It's not so accurate maybe cause of ThreadPool but can help.
Like
private bool run = true;
Thread timer = new Thread(Run);
timer.Start();
And define Run
private void Run()
{
while(run)
{
// Call function
Thread.Sleep(1000); //Time in millis
}
}
if you get cross-thread exception try to use for loop instead of foreach or lock your resources.
I have a windows service running. Within it the task runs currently at 7pm every day.
What is the best way to have it run say fir example at 9.45am, 11.45am, 2pm, 3.45pm, 5pm and 5.45pm.
I know i can have scheduled task to run the function but i would like to know how to do this within my windows service. Current code below:
private Timer _timer;
private DateTime _lastRun = DateTime.Now;
private static readonly log4net.ILog log = log4net.LogManager.GetLogger
(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
protected override void OnStart(string[] args)
{
// SmartImportService.WebService.WebServiceSoapClient test = new WebService.WebServiceSoapClient();
// test.Import();
log.Info("Info - Service Started");
_timer = new Timer(10 * 60 * 1000); // every 10 minutes??
_timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
_timer.Start();
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
log.Info("Info - Check time");
DateTime startAt = DateTime.Today.AddHours(19);
if (_lastRun < startAt && DateTime.Now >= startAt)
{
// stop the timer
_timer.Stop();
try
{
log.Info("Info - Import");
SmartImportService.WebService.WebServiceSoapClient test = new WebService.WebServiceSoapClient();
test.Import();
}
catch (Exception ex) {
log.Error("This is my error - ", ex);
}
_lastRun = DateTime.Now;
_timer.Start();
}
}
In case you dont want to go for cron or quartz, write a function to find time interval between now and next run and reset the timer accordingly, call this function on service start and timeelapsed event. You may do something like this (code is not tested)
System.Timers.Timer _timer;
List<TimeSpan> timeToRun = new List<TimeSpan>();
public void OnStart(string[] args)
{
string timeToRunStr = "20:45;20:46;20:47;20:48;20:49";
var timeStrArray = timeToRunStr.Split(';');
CultureInfo provider = CultureInfo.InvariantCulture;
foreach (var strTime in timeStrArray)
{
timeToRun.Add(TimeSpan.ParseExact(strTime, "g", provider));
}
_timer = new System.Timers.Timer(60*100*1000);
_timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
ResetTimer();
}
void ResetTimer()
{
TimeSpan currentTime = DateTime.Now.TimeOfDay;
TimeSpan? nextRunTime = null;
foreach (TimeSpan runTime in timeToRun)
{
if (currentTime < runTime)
{
nextRunTime = runTime;
break;
}
}
if (!nextRunTime.HasValue)
{
nextRunTime = timeToRun[0].Add(new TimeSpan(24, 0, 0));
}
_timer.Interval = (nextRunTime.Value - currentTime).TotalMilliseconds;
_timer.Enabled = true;
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
_timer.Enabled = false;
Console.WriteLine("Hello at " + DateTime.Now.ToString());
ResetTimer();
}
Consider using Quartz.net and CronTrigger.
If u are clear abt what schedule it should run..then change time interval for timer in the timeelapsed event so that it runs according to schedule..i've never tried though
I would use a background thread and make it execute an infinite loop which does your work and sleeps for 15 minutes. It would be a lot cleaner and more simple for service code than using a timer.
See this article on MSDN.