143

I want to call some method on every 5 minutes. How can I do this?

public class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("*** calling MyMethod *** ");
        Console.ReadLine();
    }

    private MyMethod()
    {
        Console.WriteLine("*** Method is executed at {0} ***", DateTime.Now);
        Console.ReadLine();
    }
}
Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
user1765862
  • 13,635
  • 28
  • 115
  • 220

11 Answers11

224
var startTimeSpan = TimeSpan.Zero;
var periodTimeSpan = TimeSpan.FromMinutes(5);

var timer = new System.Threading.Timer((e) =>
{
    MyMethod();   
}, null, startTimeSpan, periodTimeSpan);

Edit - this answer is out of date. See https://stackoverflow.com/a/70887955/426894

asawyer
  • 17,642
  • 8
  • 59
  • 87
  • 28
    Another way to set the interval is by passing in a timespan object. I think it's a little bit cleaner: [`Timespan.FromMinutes(5)`](http://msdn.microsoft.com/en-us/library/system.timespan.fromminutes.aspx) – Michael Haren Oct 22 '12 at 20:41
  • I think there's a problem with the timespan object because it's not the right type (as is), compared to just `0, 5 * 60 * 1000`. Anyway, for me it generates an error. – amiregelz Oct 14 '13 at 13:12
  • @amiregelz Go ahead and post a new question, commenting on a year old answer isn't likely to get much help for you. – asawyer Oct 14 '13 at 13:36
  • @asawyer I don't have any issue, just wanted to let you know this code gives an error. – amiregelz Oct 14 '13 at 13:52
  • @amiregelz Hmm... well I have this exact code running in production. What exactly is the error your seeing? – asawyer Oct 14 '13 at 15:10
  • @asawyer Oh then maybe it's not a real issue. It was a type error, I think the timespan returns double and the timer function needs an int or something like that. Maybe the other way around. Not something critical of course, but some people that copy the function from here might run into this problem too, I think. – amiregelz Oct 14 '13 at 17:09
  • 4
    @asawyer Unfortunately your implementation gives a compile error. `TotalMilliseconds` returns a double while the timer expects integers or `TimeSpan`. I tried to update your answer to one that employs `TimeSpan` and throws out unnecessary bloat; however, you reverted it. – André C. Andersen Feb 05 '14 at 23:09
  • 2
    @AndréChristofferAndersen Change 0 in Time constructor to TimeSpan.Zero. Code works after this. – RredCat Dec 01 '15 at 14:07
  • @RredCat Thanks! I contributed a similar solution lower down: http://stackoverflow.com/a/21590665/604048 – André C. Andersen Dec 01 '15 at 20:02
  • 2
    Code gives an error. This is the fix new System.Threading.Timer((e) => { Func(); }, null, TimeSpan.Zero, TimeSpan.FromMinutes(1).TotalMilliseconds); – Asheh Mar 11 '16 at 12:22
  • This gives a compile error for me in Visual Studio 2015. Please fix as the comments have suggested. – Joel Trauger Oct 17 '16 at 14:13
  • Important note: when I tried to implement it with TimeSpan.FromSeconds(x) it was unable to run each number of seconds only when I back to use minutes it starts working again – Misha Beskin Jan 09 '19 at 17:00
  • What is the null value? – Daniel Reyhanian May 25 '19 at 16:57
  • It is important to mention that a `System.Threading.Timer` needs to be rooted, otherwise it is eligible for garbage collection. So just storing it in a local variable `timer` will not cut it. Relevant question: [System.Threading.Timer not firing after some time](https://stackoverflow.com/questions/3635852/system-threading-timer-not-firing-after-some-time). – Theodor Zoulias Jul 15 '22 at 23:27
63

I based this on @asawyer's answer. He doesn't seem to get a compile error, but some of us do. Here is a version which the C# compiler in Visual Studio 2010 will accept.

var timer = new System.Threading.Timer(
    e => MyMethod(),  
    null, 
    TimeSpan.Zero, 
    TimeSpan.FromMinutes(5));
André C. Andersen
  • 8,955
  • 3
  • 53
  • 79
  • 12
    Commenting for posterity. It would stop when you called `Dispose()` method on the timer object. Example: `timer.Dispose()` using the code above as a reference. This will destroy the timer, however and prevent you from using it again. `timer.Change(Timeout.Infinite, Timeout.Infinite)` would be better if you want to use the timer again in the same program. – Joel Trauger Oct 17 '16 at 14:11
  • 1
    But why does MyMethod() not run when I run it in console application – Izuagbala Jul 27 '18 at 07:35
  • @Izuagbala It's hard to say why it doesn't work for you without knowing the particulars of how you have set it up. This solution was tested in a console application. – André C. Andersen Jul 27 '18 at 18:03
  • What is the null? – Daniel Reyhanian May 25 '19 at 16:57
  • @DanielReyhanian You can add an object state instead of the `null`, that is as a argument when calling the callback function (i.e., the first argument). – André C. Andersen May 26 '19 at 17:10
45

Update .NET 6

For most use cases in dotnet 6+, you should use the PeriodicTimer:

var timer = new PeriodicTimer(TimeSpan.FromSeconds(10));

while (await timer.WaitForNextTickAsync())
{
    //Business logic
}

This has several advantages, including async / await support, avoiding memory leaks from callbacks, and CancelationToken support

Further Reading

KyleMit
  • 30,350
  • 66
  • 462
  • 664
13

Start a timer in the constructor of your class. The interval is in milliseconds so 5*60 seconds = 300 seconds = 300000 milliseconds.

static void Main(string[] args)
{
    System.Timers.Timer timer = new System.Timers.Timer();
    timer.Interval = 300000;
    timer.Elapsed += timer_Elapsed;
    timer.Start();
}

Then call GetData() in the timer_Elapsed event like this:

static void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    //YourCode
}
IKavanagh
  • 6,089
  • 11
  • 42
  • 47
Maiko Kingma
  • 929
  • 3
  • 14
  • 29
5

Example of using a Timer:

using System;
using System.Timers;

static void Main(string[] args)
{
    Timer t = new Timer(TimeSpan.FromMinutes(5).TotalMilliseconds); // Set the time (5 mins in this case)
    t.AutoReset = true;
    t.Elapsed += new System.Timers.ElapsedEventHandler(your_method);
    t.Start();
}

// This method is called every 5 mins
private static void your_method(object sender, ElapsedEventArgs e)
{
    Console.WriteLine("..."); 
}
PJ3
  • 3,870
  • 1
  • 30
  • 34
4

I've uploaded a Nuget Package that can make it so simple, you can have it from here ActionScheduler

It supports .NET Standard 2.0

And here how to start using it

using ActionScheduler;

var jobScheduler = new JobScheduler(TimeSpan.FromMinutes(8), new Action(() => {
  //What you want to execute
}));

jobScheduler.Start(); // To Start up the Scheduler

jobScheduler.Stop(); // To Stop Scheduler from Running.
Ahmed Abuelnour
  • 442
  • 5
  • 13
  • Could not install package 'CrystalJobScheduler 1.0.0'. You are trying to install this package into a project that targets '.NETFramework,Version=v4.5', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author. – Aditya Bokade Mar 31 '19 at 17:20
3

Use a Timer. Timer documentation.

Chuck Conway
  • 16,287
  • 11
  • 58
  • 101
2

Using a DispatcherTimer:

 var _activeTimer = new DispatcherTimer {
   Interval = TimeSpan.FromMinutes(5)
 };
 _activeTimer.Tick += delegate (object sender, EventArgs e) { 
   YourMethod(); 
 };
 _activeTimer.Start();          
Bloggrammer
  • 921
  • 8
  • 21
1

If you need more complicated time executions such as linux cron, you can use NCrontab.

I use NCrontab in production for long time and it works perfect!

Nuget

How to use:

* * * * *
- - - - -
| | | | |
| | | | +----- day of week (0 - 6) (Sunday=0)
| | | +------- month (1 - 12)
| | +--------- day of month (1 - 31)
| +----------- hour (0 - 23)
+------------- min (0 - 59)
using NCrontab;
//...

protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
  // run every 5 minutes
  var schedule = CrontabSchedule.Parse("*/5 * * * *");
  var nextRun = schedule.GetNextOccurrence(DateTime.Now);
  logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);    
  do
  {
    if (DateTime.Now > nextRun)
    {
      logger.LogInformation("Sending notifications at: {time}", DateTimeOffset.Now);
      await DoSomethingAsync();
      nextRun = schedule.GetNextOccurrence(DateTime.Now);
    }
    await Task.Delay(1000, stoppingToken);
  } while (!stoppingToken.IsCancellationRequested);
}

Add seconds if you need:

// run every 10 secs
var schedule = CrontabSchedule.Parse("0/10 * * * * *", new CrontabSchedule.ParseOptions { IncludingSeconds = true });
Pato
  • 462
  • 2
  • 4
  • 11
1

It can be achieved by applying while loop and calling Thread.Sleep at the end of the loop.

while (true)
{
    //Your code
    Thread.Sleep(5000);
}

Make sure to include using System.Threading.

Mansour Fahad
  • 721
  • 2
  • 9
  • 23
-2
while (true)
{
    Thread.Sleep(60 * 5 * 1000);
    Console.WriteLine("*** calling MyMethod *** ");
    MyMethod();
}
Dennis Traub
  • 50,557
  • 7
  • 93
  • 108