How to create an event that fires at certain time [duplicate] - c#

I have a service written in C# (.NET 1.1) and want it to perform some cleanup actions at midnight every night. I have to keep all code contained within the service, so what's the easiest way to accomplish this? Use of Thread.Sleep() and checking for the time rolling over?

I wouldn't use Thread.Sleep(). Either use a scheduled task (as others have mentioned), or set up a timer inside your service, which fires periodically (every 10 minutes for example) and check if the date changed since the last run:
private Timer _timer;
private DateTime _lastRun = DateTime.Now.AddDays(-1);
protected override void OnStart(string[] args)
{
_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)
{
// ignore the time, just compare the date
if (_lastRun.Date < DateTime.Now.Date)
{
// stop the timer while we are running the cleanup task
_timer.Stop();
//
// do cleanup stuff
//
_lastRun = DateTime.Now;
_timer.Start();
}
}

Check out Quartz.NET. You can use it within a Windows service. It allows you to run a job based on a configured schedule, and it even supports a simple "cron job" syntax. I've had a lot of success with it.
Here's a quick example of its usage:
// Instantiate the Quartz.NET scheduler
var schedulerFactory = new StdSchedulerFactory();
var scheduler = schedulerFactory.GetScheduler();
// Instantiate the JobDetail object passing in the type of your
// custom job class. Your class merely needs to implement a simple
// interface with a single method called "Execute".
var job = new JobDetail("job1", "group1", typeof(MyJobClass));
// Instantiate a trigger using the basic cron syntax.
// This tells it to run at 1AM every Monday - Friday.
var trigger = new CronTrigger(
"trigger1", "group1", "job1", "group1", "0 0 1 ? * MON-FRI");
// Add the job to the scheduler
scheduler.AddJob(job, true);
scheduler.ScheduleJob(trigger);

A daily task? Sounds like it should just be a scheduled task (control panel) - no need for a service here.

Does it have to be an actual service? Can you just use the built in scheduled tasks in the windows control panel.

The way I accomplish this is with a timer.
Run a server timer, have it check the Hour/Minute every 60 seconds.
If it's the right Hour/Minute, then run your process.
I actually have this abstracted out into a base class I call OnceADayRunner.
Let me clean up the code a bit and I'll post it here.
private void OnceADayRunnerTimer_Elapsed(object sender, ElapsedEventArgs e)
{
using (NDC.Push(GetType().Name))
{
try
{
log.DebugFormat("Checking if it's time to process at: {0}", e.SignalTime);
log.DebugFormat("IsTestMode: {0}", IsTestMode);
if ((e.SignalTime.Minute == MinuteToCheck && e.SignalTime.Hour == HourToCheck) || IsTestMode)
{
log.InfoFormat("Processing at: Hour = {0} - Minute = {1}", e.SignalTime.Hour, e.SignalTime.Minute);
OnceADayTimer.Enabled = false;
OnceADayMethod();
OnceADayTimer.Enabled = true;
IsTestMode = false;
}
else
{
log.DebugFormat("Not correct time at: Hour = {0} - Minute = {1}", e.SignalTime.Hour, e.SignalTime.Minute);
}
}
catch (Exception ex)
{
OnceADayTimer.Enabled = true;
log.Error(ex.ToString());
}
OnceADayTimer.Start();
}
}
The beef of the method is in the e.SignalTime.Minute/Hour check.
There are hooks in there for testing, etc. but this is what your elapsed timer could look like to make it all work.

As others already wrote, a timer is the best option in the scenario you described.
Depending on your exact requirements, checking the current time every minute may not be necessary.
If you do not need to perform the action exactly at midnight, but just within one hour after midnight, you can go for Martin's approach of only checking if the date has changed.
If the reason you want to perform your action at midnight is that you expect a low workload on your computer, better take care: The same assumption is often made by others, and suddenly you have 100 cleanup actions kicking off between 0:00 and 0:01 a.m.
In that case you should consider starting your cleanup at a different time. I usually do those things not at clock hour, but at half hours (1.30 a.m. being my personal preference)

I would suggest that you use a timer, but set it to check every 45 seconds, not minute. Otherwise you can run into situations where with heavy load, the check for a particular minute is missed, because between the time the timer triggers and the time your code runs and checks the current time, you might have missed the target minute.

You can also try the TaskSchedulerLibrary here http://visualstudiogallery.msdn.microsoft.com/a4a4f042-ffd3-42f2-a689-290ec13011f8
Implement the abstract class AbstractScheduledTask and call the ScheduleUtilityFactory.AddScheduleTaskToBatch static method

For those that found the above solutions not working, it's because you may have a this inside your class, which implies an extension method which, as the error message says, only makes sense on a non-generic static class. Your class isn't static. This doesn't seem to be something that makes sense as an extension method, since it's acting on the instance in question, so remove the this.

Try this:
public partial class Service : ServiceBase
{
private Timer timer;
public Service()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
SetTimer();
}
private void SetTimer()
{
if (timer == null)
{
timer = new Timer();
timer.AutoReset = true;
timer.Interval = 60000 * Convert.ToDouble(ConfigurationManager.AppSettings["IntervalMinutes"]);
timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer.Start();
}
}
private void timer_Elapsed(object source, System.Timers.ElapsedEventArgs e)
{
//Do some thing logic here
}
protected override void OnStop()
{
// disposed all service objects
}
}

Related

Improve the Latency of my cycle in C#(.Net) application

I have a generic question regarding obtaining a very high latency. I am coding for a target device which has Windows Embedded Pro 7. So i would assume that I can get real time performance (from what I have read). I am using "System.Timers" for setting a time cycle.Below is an example in
public void updateCycle50ms( )
{
Stopwatch t = Stopwatch.StartNew();
System.TimeSpan timer50ms = System.TimeSpan.FromMilliseconds(50);
while (1 == 1)
{
// Sending Message
CANSEND(ref msg); // This function sends Message over CAN network.
while (t.Elapsed < timer50ms)
{
// do nothing
}
}
}
What I try to do is send a message every 50 milliSecond, but at the the cycle takes from 29ms to 90ms (I can see it at receiving end). Can you guys tell me why I am not able to achieve my goal. Do I need to use another .Net class or there are special classes which can be used in Windows Embedded to get Real Time Performance (or closer to it).
Try to use System.Timers.Timer class:
private System.Timers.Timer timer;
public void updateCycle50ms( )
{
// Create a timer with a 50ms interval.
timer= new System.Timers.Timer(50);
// Hook up the Elapsed event for the timer.
timer.Elapsed += (s, e) =>
{
// Sending Message
CANSEND(ref msg);
};
// Have the timer fire repeated events (true is the default)
timer.AutoReset = true;
// Start the timer
timer.Enabled = true;
// If the timer is declared in a long-running method, use KeepAlive to prevent garbage collection
// from occurring before the method ends.
// GC.KeepAlive(timer)
}

Run method in a schedule inside a Windows Service

I have a Windows Service, and I need run a method in a specific Schedules. So far I implement a class that represent a schedule.
public class SchaduleTime
{
public int Hour { get; set; }
public int Minute { get; set; }
public DateTime Next
{
get
{
var now = DateTime.Now;
var dt = now.Date;
// the time has passed to execute today?
if (Hour * 60 + Minute < now.Hour * 60 + now.Minute)
{
dt = dt.AddDays(1);
}
return new DateTime(dt.Year, dt.Month, dt.Day, Hour, Minute, 0);
}
}
}
And I create a main class that have this fields:
System.Timers.Timer timer;
private SchaduleTime[] schadules;
And run something like that in Elapsed event of the timer field:
private void TimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// do my work.
// programing next:
var nowTicks = DateTime.Now.Ticks;
// get the next schadule.
var next = schadules
.Select(s => new
{
Schadule = s,
IntervalNeeded = s.Next.Ticks - nowTicks
})
.OrderBy(o => o.IntervalNeeded)
.First();
timer.Enabled = false;
timer.Stop();
timer.Interval = (int) new TimeSpan(next.IntervalNeeded).TotalMilliseconds;
timer.Enabled = true;
timer.Start();
}
To me this seems like a kludge strategy or spaghetti code, I mean seems ugly.
Is there a way to do this using a specialized class that works with scheduling or something like Windows Task Scheduler inside .net or my approach is good and I'm freaking out?
Let's consider hypothetical situation where you got 10 schedules for 14:00. Say your timer stopped at 13:59:59, what happens is:
10 schedules claim they got 1 more second to go
elapsed handler picks first and restarts itself with 1 second interval
it stops again at 14:00 - right when all the schedules are already returning Next for the following day
As a result, you've run 1 out of your 10 jobs. Doesn't look good.
Of course, you could take list, or make limitation that only 1 job can be set for given hour. But then again, what other assumptions you need to make? Can schedules array be empty? Does it work when there's 1 million schedules? Do you have tests for this code? And so on.
Instead, you can use specialized library to do just that - Quartz. It's a simple jobs scheduler which can surely do what you're trying to implement here:
ISchedulerFactory factory= new StdSchedulerFactory();
IScheduler scheduler = factory.GetScheduler();
scheduler.Start();
// You'll have to implement class performing actual work to be done - ServiceJob
JobDetail jobDetail = new JobDetail("ServiceJob", null, typeof(ServiceJob));
Trigger trigger = TriggerUtils.MakeDailyTrigger();
// Start time could be anytime today
trigger.StartTimeUtc = DateTime.UtcNow;
trigger.Name = "ServiceTrigger";
scheduler.ScheduleJob(jobDetail, trigger);
Quartz takes care of all the timers, running specified jobs at requested time and so forth. It's easy, has good set of tutorials and well - you don't have to implement anything.
In my opinion, your approach is fine. Actually, it is sort of inspired. I would not have come up with having one timer and permanently rescheduling it.
What I would have done - and this is strictly optional, like I said, your approach is fine - is just have the timer fire every minute and check if there is something to do. With smaller time resolution, seconds or even milliseconds, I would not do that. But having your timer run every minute, just checking an in-memory-array, and going straight back to sleep in 95% of cases is hardly a terrible waste of resources. Plus, it would allow for code that is much more straightforward and easier to maintain.

How to add a timer to an app!

I have an app that I would like to update on an interval. I am looking for maybe some type of if statement or try - catch statement. I already have a foreach statement in the same class, but i dont think I can put in there? I would also like to set it up so that the user can change the refresh rate. Any help is appreciated. Thanks
Here is the method that I would like to put the timer in...
private void _UpdatePortStatus(string[] files)
{
foreach (string file in files)
{
PortStatus ps = new PortStatus();
ps.ReadXml(new StreamReader(file));
if (!_dicPortStatus.ContainsKey(ps.General[0].Group))
{
_dicPortStatus.Add(ps.General[0].Group, ps);
}
PortStatus psOrig = _dicPortStatus[ps.General[0].Group];
foreach (PortStatus.PortstatusRow psr in ps.Portstatus.Rows)
{
DataRow[] drs = psOrig.Portstatus.Select("PortNumber = '" + psr.PortNumber + "'");
if (drs.Length == 1)
{
DateTime curDt = DateTime.Parse(drs[0]["LastUpdateDateTimeUTC"].ToString());
DateTime newDt = psr.LastUpdateDateTimeUTC;
if (newDt > curDt)
{
drs[0]["LastUpdateDateTimeUTC"] = newDt;
}
}
else if (drs.Length == 0)
{
psOrig.Portstatus.ImportRow(psr);
}
else
{
throw new Exception("More than one of the same portnumber on PortStatus file: " + file);
}
}
}
}
Look at the System.Timer class. You basically set an interval (eg. 10000 milliseconds) and it will raise an event every time that interval time passes.
To allow the use to change the refresh rate, write a method that receives input from the user and use that to update the TimerInterval. Note that the TimerInterval is in miliseconds, so you may need to convert to that from whatever the user input.
So, from the example, the event will be raised every 10 seconds:
System.Timers.Timer aTimer = new System.Timers.Timer(10000); //10 seconds
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Enabled = true; // Starts the Timer
// Specify what you want to happen when the Elapsed event is raised
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
//Perform update
_UpdatePortStatus(files);
}
UPDATE: In response to your posted code, it appears you simply want to call _UpdatePortStatus to update the port status at regular intervals (see the updated example above).
One important point you need to bear in mind though is that the Timer will run on a separate thread, and as such could raise the event again before it has finished running from the last time if it takes more than the interval time to run.
Use System.Timers.Timer, System.Threading.Timer or System.Windows.Forms.Timer ... depending on what exactly it is that you "would like to update on an interval."
See the following articles:
http://www.intellitechture.com/System-Windows-Forms-Timer-vs-System-Threading-Timer-vs-System-Timers-Timer/
http://www.yoda.arachsys.com/csharp/threads/timers.shtml
Your question is somewhat vague as there an many different methods of achieving what you want to do. However in the simplest terms you need to create a System.Threading.Timer that ticks on whatever frequency you define, for example:
private System.Threading.Timer myTimer;
private void StartTimer()
{
myTimer = new System.Threading.Timer(TimerTick, null, 0, 5000);
}
private void TimerTick(object state)
{
Console.WriteLine("Tick");
}
In this example the timer will 'tick' every 5 seconds and perform whatever functionality you code into the TimerTick method. If the user wants to change the frequency then you would destroy the current timer and initialise with the new frequency.
All this said, I must stress that this is the simplest of implementation and may not suit your needs.

C# Timer vs Thread in Service

I have a Service that hits a database every 10 sec and gets the data if there is any. The thing is that processing this data can take up to 30 sec. If I use a Timer with 10 sec interval the service will get the same data twice.
The effect i´m trying to achieve(Just for visualization):
while(true)
{
if(Getnrofrows() > 0)
do stuff
else
sleep for 10 sec
}
Ppl saying Thread.Sleep is a bad idea in production services, how do I do this with timers?
/mike
Did you try to set Timer property auto reset to false, and enabling timer again when process of refreshing data is over
using System;
public class PortChat
{
public static System.Timers.Timer _timer;
public static void Main()
{
_timer = new System.Timers.Timer();
_timer.AutoReset = false;
_timer.Interval = 100;
_timer.Elapsed += new System.Timers.ElapsedEventHandler(_timer_Elapsed);
_timer.Enabled = true;
Console.ReadKey();
}
static void _timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//Do database refresh
_timer.Enabled = true;
}
}
I don't see any problems with using Sleep at all other than you might end up with ugly code.
To answer your question:
public class MyTest
{
System.Threading.Timer _timer;
public MyTest()
{
_timer = new Timer(WorkMethod, 15000, 15000);
}
public void WorkMethod()
{
_timer.Change(Timeout.Infinite, Timeout.Infinite); // suspend timer
// do work
_timer.Change(15000, 15000); //resume
}
}
There is nothing wrong with this approach. A sleeping thread does not consume any CPU cycles.
If you need to do something exactly every X seconds, a timer is the way to go. If, on the other hand, you want to pause for X seconds, then Thread.Sleep is appropriate.
Thread.Sleep is not bad in itself in a service, just that you need to be responsive to service commands, so your worker thread should not go to sleep for an hour, but rather needs to sleep for short periods of time and then wake up and listen if the service controller part of the service is telling it to stop for some reason.
You want to make it so that if the admin tells your service to stop, it'll stop quickly enough so that it won't get any timeout messages where the admin can't be sure that your service is stopped and it's safe to reboot the machine or similar.

How can I raise an event every hour (or specific time interval each hour) in .NET?

I'm working on a little web crawler that will run in the system tray and crawl a web site every hour on the hour.
What is the best way to get .NET to raise an event every hour or some other interval to perform some task. For example I want to run an event every 20 minutes based on the time. The event would be raised at:
00:20
00:40
01:00
01:20
01:40
and so on. The best way I can think of to do this is by creating a loop on a thread, that constantly checks if the time is divisible by a given interval and raises a callback event if the time is reached. I feel like there has got to be a better way.
I'd use a Timer but I'd prefer something that follows a "schedule" that runs on the hour or something along those lines.
Without setting up my application in the windows task scheduler is this possible?
UPDATE:
I'm adding my algorithm for calculating the time interval for a timer. This method takes a "minute" parameter, which is what time the timer should trigger a tick. For example, if the "minute" parameter is 20, then the timer will tick at the intervals in the timetable above.
int CalculateTimerInterval(int minute)
{
if (minute <= 0)
minute = 60;
DateTime now = DateTime.Now;
DateTime future = now.AddMinutes((minute - (now.Minute % minute))).AddSeconds(now.Second * -1).AddMilliseconds(now.Millisecond * -1);
TimeSpan interval = future - now;
return (int)interval.TotalMilliseconds;
}
This code is used as follows:
static System.Windows.Forms.Timer t;
const int CHECK_INTERVAL = 20;
static void Main()
{
t = new System.Windows.Forms.Timer();
t.Interval = CalculateTimerInterval(CHECK_INTERVAL);
t.Tick += new EventHandler(t_Tick);
t.Start();
}
static void t_Tick(object sender, EventArgs e)
{
t.Interval = CalculateTimerInterval(CHECK_INTERVAL);
}
System.Timers.Timer. If you want to run at specific times of the day, you will need to figure out how long it is until the next time and set that as your interval.
This is just the basic idea. Depending on how precise you need to be you can do more.
int minutes = DateTime.Now.Minute;
int adjust = 10 - (minutes % 10);
timer.Interval = adjust * 60 * 1000;
You may find help from Quartz.net http://quartznet.sourceforge.net/
Here is an example of a lightweight system using thread timing and an asynch call.
I know there are some downsides, but I like using this instead of a timer when kicking off a long running process (like schedualed backend services). Since it runs inline in the timer thread, you don't have to worry about it getting kicked off again before the the original call has finished. This could be extended quite a bit to make it use an array of datetimes as the trigger times or add some more abilities to it. I am sure some of you guys out there know some better ways.
public Form1()
{
InitializeComponent();
//some fake data, obviously you would have your own.
DateTime someStart = DateTime.Now.AddMinutes(1);
TimeSpan someInterval = TimeSpan.FromMinutes(2);
//sample call
StartTimer(someStart,someInterval,doSomething);
}
//just a fake function to call
private bool doSomething()
{
DialogResult keepGoing = MessageBox.Show("Hey, I did something! Keep Going?","Something!",MessageBoxButtons.YesNo);
return (keepGoing == DialogResult.Yes);
}
//The following is the actual guts.. and can be transplanted to an actual class.
private delegate void voidFunc<P1,P2,P3>(P1 p1,P2 p2,P3 p3);
public void StartTimer(DateTime startTime, TimeSpan interval, Func<bool> action)
{
voidFunc<DateTime,TimeSpan,Func<bool>> Timer = TimedThread;
Timer.BeginInvoke(startTime,interval,action,null,null);
}
private void TimedThread(DateTime startTime, TimeSpan interval, Func<bool> action)
{
bool keepRunning = true;
DateTime NextExecute = startTime;
while(keepRunning)
{
if (DateTime.Now > NextExecute)
{
keepRunning = action.Invoke();
NextExecute = NextExecute.Add(interval);
}
//could parameterize resolution.
Thread.Sleep(1000);
}
}
Another strategy for this would be to record the LAST TIME that the process was run and determine if your desired interval has elapsed since that time. In this strategy, you would code your event to fire if the elapsed time is equal to OR GREATER THAN the desired interval. In this way you can handle instances where long intervals (once per day, for example) could be missed if the computer were to be down for some reason.
So for example:
lastRunDateTime = 5/2/2009 at 8pm
I want to run my process every 24 hours
On a timer event, check whether 24 hours OR MORE passed since the last time the process was run.
If yes, run the process, update lastRunDateTime by adding the desired interval to it (24 hours in this case, but whatever you need it to be)
Obviously, for this to recover after the system has gone down, you will need to store lastRunDateTime in a file or database somewhere so the program could pick up where it left off on recovery.
System.Windows.Forms.Timer (or System.Timers.Timer)
but since now you say you don't want to use Timers, you can run a lightweight wait process on another thread (check time, sleep a few seconds, check time again...) or make a component that raises an event (using a lightweight wait process) on certain scheduled times or intervals
The following should do the trick.
static void Main(string[] Args)
{
try
{
MainAsync().GetAwaiter().GetResult();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
static async Task MainAsync()
{
CancellationTokenSource tokenSource = new CancellationTokenSource();
// Start the timed event here
StartAsync(tokenSource.Token);
Console.ReadKey();
tokenSource.Cancel();
tokenSource.Dispose();
}
public Task StartAsync(CancellationToken cancellationToken)
{
var nextRunTime = new DateTime();
switch (DateTime.Now.AddSeconds(1) < DateTime.Today.AddHours(12)) // add a second to current time to account for time needed to setup the task.
{
case true:
nextRunTime = DateTime.Today.AddHours(12); // Run at midday today.
break;
case false:
nextRunTime = DateTime.Today.AddDays(1).AddHours(12); // Run at midday tomorrow.
break;
}
var firstInterval = nextRunTime.Subtract(DateTime.Now);
Action action = () =>
{
// Run the task at the first interval, then run the task again at midday every day.
_timer = new Timer(
EventMethod,
null,
firstInterval,
DateTime.Today.AddDays(1).AddHours(12).Subtract(DateTime.Now)
);
};
// no need to await this call here because this task is scheduled to run later.
Task.Run(action);
return Task.CompletedTask;
}
private async void EventMethod(object state)
{
// do work
}
My goal is to run an import around 03:00 every night.
Here's my approach, using System.Timers.Timer:
private Timer _timer;
private Int32 _hours = 0;
private Int32 _runAt = 3;
protected override void OnStart(string[] args)
{
_hours = (24 - (DateTime.Now.Hour + 1)) + _runAt;
_timer = new Timer();
_timer.Interval = _hours * 60 * 60 * 1000;
_timer.Elapsed += new ElapsedEventHandler(Tick);
_timer.Start();
}
void Tick(object sender, ElapsedEventArgs e)
{
if (_hours != 24)
{
_hours = 24;
_timer.Interval = _hours * 60 * 60 * 1000;
}
RunImport();
}

Categories