How can I run some function every 5th minute? Example: I want run sendRequest()
only at time 14:00, 14:05, 14:10 etc.
I would like to do it programmatically, in C#. The application is a Windows service.
How can I run some function every 5th minute? Example: I want run sendRequest()
only at time 14:00, 14:05, 14:10 etc.
I would like to do it programmatically, in C#. The application is a Windows service.
The answer posted six years ago is useful. However, IMHO with modern C# it is now better to use the Task
-based API with async
and await
. Also, I differ a little on the specifics of the implementation, such as how to manage the delay computation and how to round the current time to the next five minute interval.
First, let's assume the sendRequest()
method returns void
and has no parameters. Then, let's assume that the basic requirement is to run it roughly every five minutes (i.e. it's not that important that it run exactly on five-minute divisions of the hour). Then that can be implemented very easily, like this:
async Task RunPeriodically(Action action, TimeSpan interval, CancellationToken token)
{
while (true)
{
action();
await Task.Delay(interval, token);
}
}
It can be called like this:
CancellationTokenSource tokenSource = new CancellationTokenSource();
Task timerTask = RunPeriodically(sendRequest, TimeSpan.FromMinutes(5), tokenSource.Token);
When tokenSource.Cancel()
is called, the loop will be interrupted by the TaskCanceledException
thrown at the await Task.Delay(...)
statement. Otherwise, the sendRequest()
method will be called every five minutes (with it being called immediately when the RunPeriodically()
method is called…you can reorder the statements in the loop if you want it to wait the first time too).
That's the simplest version. If instead you do want to perform the action exactly on five minute intervals, you can do something similar, but compute the next run time and delay for an appropriate amount of time. For example:
// private field somewhere appropriate; it would probably be best to put
// this logic into a reusable class.
DateTime _nextRunTime;
async Task RunPeriodically(Action action,
DateTime startTime, TimeSpan interval, CancellationToken token)
{
_nextRunTime = startTime;
while (true)
{
TimeSpan delay = _nextRunTime - DateTime.UtcNow;
if (delay > TimeSpan.Zero)
{
await Task.Delay(delay, token);
}
action();
_nextRunTime += interval;
}
}
Called like this:
CancellationTokenSource tokenSource = new CancellationTokenSource();
DateTime startTime = RoundCurrentToNextFiveMinutes();
Task timerTask = RunPeriodically(sendRequest,
startTime, TimeSpan.FromMinutes(5), tokenSource.Token);
Where the helper method RoundCurrentToNextFiveMinutes()
looks like this:
DateTime RoundCurrentToNextFiveMinutes()
{
DateTime now = DateTime.UtcNow,
result = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0);
return result.AddMinutes(((now.Minute / 5) + 1) * 5);
}
In either example, the timerTask
object can be used to monitor the state of the loop. In most cases, it's probably not needed. But if you want to be able to, e.g. await
until some other part of the code cancels the loop, this object is what you'd use.
Note that the Task.Delay()
method does use a timer in its implementation. The above is not suggested for the purpose of avoiding the use of a timer, but rather to show an implementation of the original goal using the modern C# async
/await
features. This version will mesh more cleanly with other code that is already using async
/await
.
CancellationTokenSource
for the token you pass to the method, to interrupt the timing loop. In your case, when you've determined that "there are no updates to the DB or if a certain row message is inserted", that's when you'd cancel the token to interrupt the repeating behavior. If you need more help than that, you should post a new question to the site, providing a good minimal reproducible example that shows clearly what you've tried, and explain specifically and precisely what it is you're having trouble getting to work. –
Josettejosey Use System.Threading.Timer
. You can specify a method to call periodically.
Example:
Timer timer = new Timer(Callback, null, TimeSpan.Zero, TimeSpan.FromMinutes(5));
public void Callback(object state) {
Console.WriteLine("The current time is {0}", DateTime.Now);
}
You can use the second parameter to pass state to the callback.
Note that you'll need to keep your application alive somehow (e.g., run it as a service).
As for how to make sure that it runs at hh:mm
where mm % 5 == 0
, you can do the following.
DateTime now = DateTime.Now;
int additionalMinutes = 5 - now.Minute % 5;
if(additionalMinutes == 0) {
additionalMinutes = 5;
}
var nearestOnFiveMinutes = new DateTime(
now.Year,
now.Month,
now.Day,
now.Hour,
now.Minute,
0
).AddMinutes(additionalMinutes);
TimeSpan timeToStart = nearestOnFiveMinutes.Subtract(now);
TimeSpan tolerance = TimeSpan.FromSeconds(1);
if (timeToStart < tolerance) {
timeToStart = TimeSpan.Zero;
}
var Timer = new Timer(callback, null, timeToStart, TimeSpan.FromMinutes(5));
Note that the tolerance
is necessary in case this code is executing when now
is very close to the nearest hh:mm
with mm % 5 == 0
. You can probably get away with a value smaller than one second but I'll leave that to you.
System.Windows.Timer
. The timer you're showing is System.Threading.Timer
. –
Homothermal Timeout.Infinite
for the last parameter), re-compute the due time after each tick, and call Timer.Change
with the new due time. –
Homothermal The answer posted six years ago is useful. However, IMHO with modern C# it is now better to use the Task
-based API with async
and await
. Also, I differ a little on the specifics of the implementation, such as how to manage the delay computation and how to round the current time to the next five minute interval.
First, let's assume the sendRequest()
method returns void
and has no parameters. Then, let's assume that the basic requirement is to run it roughly every five minutes (i.e. it's not that important that it run exactly on five-minute divisions of the hour). Then that can be implemented very easily, like this:
async Task RunPeriodically(Action action, TimeSpan interval, CancellationToken token)
{
while (true)
{
action();
await Task.Delay(interval, token);
}
}
It can be called like this:
CancellationTokenSource tokenSource = new CancellationTokenSource();
Task timerTask = RunPeriodically(sendRequest, TimeSpan.FromMinutes(5), tokenSource.Token);
When tokenSource.Cancel()
is called, the loop will be interrupted by the TaskCanceledException
thrown at the await Task.Delay(...)
statement. Otherwise, the sendRequest()
method will be called every five minutes (with it being called immediately when the RunPeriodically()
method is called…you can reorder the statements in the loop if you want it to wait the first time too).
That's the simplest version. If instead you do want to perform the action exactly on five minute intervals, you can do something similar, but compute the next run time and delay for an appropriate amount of time. For example:
// private field somewhere appropriate; it would probably be best to put
// this logic into a reusable class.
DateTime _nextRunTime;
async Task RunPeriodically(Action action,
DateTime startTime, TimeSpan interval, CancellationToken token)
{
_nextRunTime = startTime;
while (true)
{
TimeSpan delay = _nextRunTime - DateTime.UtcNow;
if (delay > TimeSpan.Zero)
{
await Task.Delay(delay, token);
}
action();
_nextRunTime += interval;
}
}
Called like this:
CancellationTokenSource tokenSource = new CancellationTokenSource();
DateTime startTime = RoundCurrentToNextFiveMinutes();
Task timerTask = RunPeriodically(sendRequest,
startTime, TimeSpan.FromMinutes(5), tokenSource.Token);
Where the helper method RoundCurrentToNextFiveMinutes()
looks like this:
DateTime RoundCurrentToNextFiveMinutes()
{
DateTime now = DateTime.UtcNow,
result = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0);
return result.AddMinutes(((now.Minute / 5) + 1) * 5);
}
In either example, the timerTask
object can be used to monitor the state of the loop. In most cases, it's probably not needed. But if you want to be able to, e.g. await
until some other part of the code cancels the loop, this object is what you'd use.
Note that the Task.Delay()
method does use a timer in its implementation. The above is not suggested for the purpose of avoiding the use of a timer, but rather to show an implementation of the original goal using the modern C# async
/await
features. This version will mesh more cleanly with other code that is already using async
/await
.
CancellationTokenSource
for the token you pass to the method, to interrupt the timing loop. In your case, when you've determined that "there are no updates to the DB or if a certain row message is inserted", that's when you'd cancel the token to interrupt the repeating behavior. If you need more help than that, you should post a new question to the site, providing a good minimal reproducible example that shows clearly what you've tried, and explain specifically and precisely what it is you're having trouble getting to work. –
Josettejosey Use System.Threading.Timer:
var timer = new Timer(TimerTick, null, TimeSpan.Zero, new TimeSpan(0, 0, 0, 1));
int lastMinute = 1;
void TimerTick(object state)
{
var minute = DateTime.Now.Minutes;
if (minute != lastMinute && minute % 5 == 0)
{
lastMinute = minute;
//do stuff
}
}
This might look somewhat clumsy and inefficient since it has to call every second, but the actual number of CPU cycles that get used to perform the check once a second is totally negligible on virtually any hardware.
(Sorry if the code isn't 100% correct; I don't have an IDE on me right now.
TimeSpan.FromSeconds(1)
? It's much easier to understand. –
Homothermal You can make a thread which include a loop like this
void Runner(){
while(1){
Thread t = new thread( target_method );
t.start();
sleep(5 * 60 * 1000);
}
}
It's a bit quick and dirty but gonna do the job :)
Thread.Sleep
takes its argument in milliseconds, so if you do this your computer is going to be sad... –
Reface you could have a thread running that first
This class is everythign you need, you just setup the amount of time between delegate callings and your delegate and thats it :)
http://msdn.microsoft.com/en-us/library/system.threading.timer.aspx
You better give you own Thread that executes the method a condition
While(programStatus == ProgramStatus.Working)
{
While (true)
{
// Do your stuff
}
Thread.Sleep(TheTimeYouWantTheThreadToWaitTillTheNextOperation);
}
What you are looking for is code that implements 'cron' jobs. There are a few libraries out there that do this (quartz.net is one of them). I found that many of them are bulky and have many features. Here is a leaner implementation that I have used in some projects:
http://blog.bobcravens.com/2009/10/an-event-based-cron-scheduled-job-in-c/
P.S. My server appears to be down right now. I am working on that.
Hope that helps.
Bob
There are a few ways to do this, you can create a timer that runs every 5 minutes and start it when the time reaches one of the 5 minute intervals, or have it run every few seconds and check if the time is divisible by 5
System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer(); // create a new timer
timer.interval = 300000; //300000 = 5 minutes
then create a tick function and add an event handler
timer.Tick += new EventHandler(TimerTickHandler); //add the event handler
timer.Start(); //start the timer
I agree with Peter Duniho - modern C# is far better at this stuff.
I would suggest using Microsoft's Reactive Framework (NuGet "System.Reactive") and then you can do this:
IObservable<long> timer =
Observable
.Defer(() =>
{
var now = DateTimeOffset.Now;
var result = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, 0, 0, now.Offset);
result = result.AddMinutes(((now.Minute / 5) + 1) * 5);
return Observable.Timer(result, TimeSpan.FromMinutes(5.0));
});
timer.Subscribe(x =>
{
/* Your code here that run on the 5 minute every 5 minutes. */
});
I get this kind of result:
2016/08/11 14:40:00 +09:30 2016/08/11 14:45:00 +09:30 2016/08/11 14:50:00 +09:30
http://www.csharphelp.com/2006/02/c-timer-demo/
Few tutorials on the time in C#
© 2022 - 2024 — McMap. All rights reserved.