簡體   English   中英

設置代碼以每24小時運行一次

[英]Set up code to run every 24 hours

對於工作中的輔助項目,我試圖編寫一段代碼,該代碼在特定時間每24小時運行一次。 我的老板要求我使用無限循環而不是C#的計時器類,所以這是我要處理的主要約束。 我的問題是該代碼將在最初的24小時內正常工作(即它將在​​我設置的那一天運行該代碼),但是此后將不會更新。 我沒有被拋出任何異常或錯誤,所以我假設這只是我的邏輯問題。

這是我現在擁有的代碼的要點。

int i = 0;
while (true)
{
    DateTime currentdate = DateTime.Now;
    String time = currentdate.ToString("HH:mm");

    if ((time == "23:50" || time == "23:51") && i == 0)
    {
        HistoricalAverageCollection HAC = new HistoricalAverageCollection();
        HAC.ExecHAC();

        HistoricalAverageError HAE = new HistoricalAverageError();
        HAE.ExecHAE();
        FourWeekAverageCollection FWAC = new FourWeekAverageCollection();
        FWAC.ExecFWAC();
        FourWeekAverageError FWAE = new FourWeekAverageError();
        FWAE.ExecFWAE();

        DomainsReturningZeroTwentyFourHours DRZ = 
            new DomainsReturningZeroTwentyFourHours();
        DRZ.ExecDomainsReturningZero();

        context.SaveChanges();

        //Program should update every 24 horus
        i = 1;

        Console.Write("Updated The Historical Averages In The Data Base at...");
        Console.Write(DateTime.Now);
        Console.WriteLine("i is -> {0}", i);
        Console.Read();
    }
    else if (time == "06:00" && i == 1)
    {
        ReportEmail Report = new ReportEmail();
        Report.CreateAndSendReport();
        i = 0;
        Console.Write("counter reset. I is now -> {0} /n Email Sent",i);
        Console.Read();
    }
}

該代碼設置為在晚上11:50調用一堆tsql存儲過程,然后在早上6點根據該數據發送電子郵件報告。 但是,它只會運行一次,我發現自己在一兩天后的早晨醒來,發現沒有電子郵件發送。

任何幫助,將不勝感激 :)

我會贊同許多意見,並提出其他更合適的方法,但是我認為您的問題在於:

Console.Read();

從文檔中:

當您鍵入輸入字符時,Read方法將阻止其返回; 當您按Enter鍵時,它將終止。

因此,它將阻止等待永遠不會出現的條目。

保留一個指示“下一個”日期時間運行的時間變量。

在循環中,只需檢查之后的當前時間並運行代碼即可。然后將變量重置為下一天,即現在+ 24小時。

另一個答案表明問題出在以下方面:

Console.Read();

需要刪除的

如果您真的想手動完成所有操作而不使用計時器或現有的調度程序功能,我建議您更加嚴格一些,並自己構建一個簡單的任務調度程序類。 您需要的零件:

  • 一個用於存儲每個任務的類,其中包括要為該任務執行的代碼以及每個任務應何時運行的時間表。
  • 此類任務清單
  • 一種計算下一個截止日期何時來自任務列表的方法,因此您知道睡眠時間。
  • 睡眠的SemaphoreSlim(而不是Thread.Sleep()
    • 使用SemaphoreSlim是因為它可以作為Thread.Sleep()通過傳遞一個等待時間(如果該信號量從未釋放過Thread.Sleep()而起作用; 也是因為如果您的調度程序確定已添加新任務,並且可以喚醒它以重新評估下一個截止日期,則可以手動釋放它。

我建議您將截止日期存儲在UTC中,並使用UTC時間進行大部分時間計算工作,這樣就不會對時區更改或DST造成混淆。

您還應該考慮不僅在下一個截止日期之前一直處於休眠狀態,以防萬一有NTP更新到PC的系統時間。 考慮一次最多睡1小時。

一些讓您入門的要點:

public void Run()
{
    this.running = true;

    do
    {
        DateTime nextDeadlineUtc;
        ScheduledTask nextTask;
        bool deadlineExpired;

        nextDeadlineUtc = ComputeNextDeadline( out nextTask );

        deadlineExpired = WaitForDeadline( nextDeadlineUtc );

        if( deadlineExpired )
        {
            // We hit the deadline. Execute the task and move on.
            nextTask.Execute();
        }
        else
        {
            // We were woken up before the deadline expired. That means either we're shutting
            // down, or we need to recompute our next deadline because the schedule changed.
            // To deal with this, just do nothing. We'll loop back around and either find out
            // we're being asked to stop, or we'll recompute the next deadline.
        }
    }
    while( this.running );
}

/// <summary>
/// Sleeps until the deadline has expired.
/// </summary>
/// <param name="nextDeadlineUtc">The next deadline, in UTC</param>
/// <returns>
/// True if the deadline has elapsed; false if the scheduler should re-examine its next deadline.
/// </returns>
private bool WaitForDeadline( DateTime nextDeadlineUtc )
{
    TimeSpan wait;
    bool incompleteDeadline;
    bool acquired;

    wait = ComputeSleepTime( nextDeadlineUtc, out incompleteDeadline );

    acquired = this.waiter.Wait( wait );

    if( acquired || incompleteDeadline )
    {
        // Either:
        // - We were manually woken up early by someone releasing the semaphore.
        // - The timeout expired, but that's because we didn't wait for the complete time.
        // 
        // Either way, the deadline didn't expire.
        return false;
    }
    else
    {
        // The deadline occurred. 
        return true;
    }
}

private TimeSpan ComputeSleepTime( DateTime nextDeadlineUtc, out bool incompleteDeadline )
{
    TimeSpan totalRemaining = nextDeadlineUtc - DateTime.UtcNow;

    if( totalRemaining.Ticks < 0 )
    {
        // Were already out of time.
        incompleteDeadline = false;
        return TimeSpan.FromTicks( 0 );
    }
    else if( totalRemaining.TotalHours <= 1.01 )
    {
        // Just sleep the whole of the remainder.
        incompleteDeadline = false;
        return totalRemaining;
    }
    else
    {
        // More than one hour to sleep. Sleep for at most one hour, but tell the sleeper that
        // there's still more time left.
        incompleteDeadline = true;
        return TimeSpan.FromHours( 1.0 );
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM