Executing method every hour on the hour

2019-02-09 05:08发布

I want to execute a method every hour on the hour. I wrote some code,but it is not enough for my aim. Below code is working every 60 minutes.

public void Start()
{
    System.Threading.Timer timerTemaUserBilgileri = new System.Threading.Timer(new System.Threading.TimerCallback(RunTakip), null, tmrTemaUserBilgileri, 0);
}

public void RunTakip(object temauserID)
{
    try 
    {
        string objID = "6143566557387";
        EssentialMethod(objID);
        TimeSpan span = DateTime.Now.Subtract(lastRunTime);
        if (span.Minutes > 60)
        {
            tmrTemaUserBilgileri = 1 * 1000;
            timerTemaUserBilgileri.Change(tmrTemaUserBilgileri, 0);
        }
        else
        {
            tmrTemaUserBilgileri = (60 - span.Minutes) * 60 * 1000;
            timerTemaUserBilgileri.Change(tmrTemaUserBilgileri, 0);
        }
        watch.Stop();
        var elapsedMs = watch.ElapsedMilliseconds;
    }
    catch (Exception ex)
    {
        timerTemaUserBilgileri.Change(30 * 60 * 1000, 0);
        Utils.LogYaz(ex.Message.ToString());
    }
}

public void EssentialMethod(objec obj)
{
    //some code
    lastRunTime = DateTime.Now;
    //send lastruntime to sql 
}

标签: c# timer
7条回答
爷的心禁止访问
2楼-- · 2019-02-09 05:42

If you want your code to be executed every 60 minutes:

aTimer = new System.Timers.Timer(60 * 60 * 1000); //one hour in milliseconds
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
    //Do the stuff you want to be done every hour;
}

if you want your code to be executed every hour (i.e. 1:00, 2:00, 3:00) you can create a timer with some small interval (let's say a second, depends on precision you need) and inside that timer event check if an hour has passed

aTimer = new System.Timers.Timer(1000); //One second, (use less to add precision, use more to consume less processor time
int lastHour = DateTime.Now.Hour;
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
    if(lastHour < DateTime.Now.Hour || (lastHour == 23 && DateTime.Now.Hour == 0))
     {
           lastHour = DateTime.Now.Hour;
           YourImportantMethod(); // Call The method with your important staff..
     }

}
查看更多
走好不送
3楼-- · 2019-02-09 05:42

Why is everyone trying to handle this problem with a timer?

you're doing two things... waiting until the top of the hour and then running your timer every hour on the hour.

I have a windows service where I needed this same solution. I did my code in a very verbose way so that it is easy to follow for anyone. I know there are many shortcuts that can be implemented, but I leave that up to you.

private readonly Timer _timer;
/// starts timer
internal void Start()
{
    int waitTime = calculateSleepTime();

    System.Threading.Thread.Sleep(waitTime);

    object t = new object();

    EventArgs e = new EventArgs();

    CheckEvents(t, e);

    _timer.Start();
}

///  runs business logic everytime timer goes off
internal void CheckEvents(object sender, EventArgs e)
{
    //  do your logic here      
}

///  Calculates how long to wait until the top of the hour
private int calculateSleepTime()
{
    DateTime now = DateTime.Now;

    int minutes = now.Minute * 60 * 1000;

    int seconds = now.Second * 1000;

    int substrahend = now.Millisecond + seconds + minutes;

    int minuend = 60 * 60 * 1000;

    return minuend - substrahend;
}         
查看更多
闹够了就滚
4楼-- · 2019-02-09 05:50

Just a small comment based on /Anarion's solution that I couldn't fit into a comment.

you can create a timer with some small interval (let's say a second, depends on precision you need)

You don't need it to go with any precision at all, you're thinking "how do I check this hour is the hour I want to fire". You could alternatively think "How do I check the next hour is the hour I want to fire" - once you think like that you realise you don't need any precision at all, just tick once an hour, and set a thread for the next hour. If you tick once an hour you know you'll be at some point before the next hour.

Dim dueTime As New DateTime(Date.Today.Year, Date.Today.Month, Date.Today.Day, DateTime.Now.Hour + 1, 0, 0)
Dim timeRemaining As TimeSpan = dueTime.Subtract(DateTime.Now)

t = New System.Threading.Timer(New System.Threading.TimerCallback(AddressOf Method), Nothing, CType(timeRemaining.TotalMilliseconds, Integer), System.Threading.Timeout.Infinite)
查看更多
Viruses.
5楼-- · 2019-02-09 05:51

I agree with Señor Salt that the chron job should be the first choice. However, the OP asked for every hour on the hour from c#. To do that, I set up the first timed event to fire on the hour:

int MilliSecondsLeftTilTheHour()
{
    int interval;

    int minutesRemaining = 59 - DateTime.Now.Minute;
    int secondsRemaining = 59 - DateTime.Now.Second;
    interval = ((minutesRemaining * 60) + secondsRemaining) * 1000;

    // If we happen to be exactly on the hour...
    if (interval == 0)
    {
        interval = 60 * 60 * 1000;
    }
    return interval;
}

Timer timer = new Timer();
timer.Tick += timer_Tick;
timer.Enabled = true;
timer.Interval = MilliSecondsLeftTilTheHour();

The problem now is that if the above timer.Interval happens to be 45 minutes and 32 seconds, then the timer will continue firing every 45:32 not just the first time. So, inside the timer_Tick method, you have to readjust the timer.Interval to one hour.

 void timer_Tick(object sender, EventArgs e)
 {
     // The Interval could be hard wired here to  60 * 60 * 1000 but on clock 
     // resets and if the job ever goes longer than an hour, why not
     // recalculate once an hour to get back on track.
     timer.Interval = MilliSecondsLeftTilTheHour();
     DoYourThing();
 }
查看更多
别忘想泡老子
6楼-- · 2019-02-09 05:52

What about trying the below code, the loop is determined to save your resources, and it is running every EXACT hour, i.e. with both minutes and seconds (and almost milliseconds equal to zero:

using System;
using System.Threading.Tasks;

namespace COREserver{
    public static partial class COREtasks{   // partial to be able to split the same class in multiple files
        public static async void RunHourlyTasks(params Action[] tasks)
        {
            DateTime runHour = DateTime.Now.AddHours(1.0);
            TimeSpan ts = new TimeSpan(runHour.Hour, 0, 0);
            runHour = runHour.Date + ts;


            Console.WriteLine("next run will be at: {0} and current hour is: {1}", runHour, DateTime.Now);
            while (true)
            {
                TimeSpan duration = runHour.Subtract(DateTime.Now);
                if(duration.TotalMilliseconds <= 0.0)
                { 
                    Parallel.Invoke(tasks);
                    Console.WriteLine("It is the run time as shown before to be: {0} confirmed with system time, that is: {1}", runHour, DateTime.Now);
                    runHour = DateTime.Now.AddHours(1.0);
                    Console.WriteLine("next run will be at: {0} and current hour is: {1}", runHour, DateTime.Now);
                    continue;
                }
                int delay = (int)(duration.TotalMilliseconds / 2);
                await Task.Delay(30000);  // 30 seconds
            }
        }
    }
}
查看更多
疯言疯语
7楼-- · 2019-02-09 05:53

Use a Cron Job on the server to call a function at the specified interval

Heres a link http://www.thesitewizard.com/general/set-cron-job.shtml

查看更多
登录 后发表回答