设置代码每24小时运行一次

时间:2017-06-02 13:08:20

标签: c#

对于正在工作的辅助项目,我正在尝试使用一段代码,该代码在某个时间每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 Pm调用一堆tsql存储过程,然后在早上6点发送基于该数据的电子邮件报告。但是,它只运行一次,我发现自己在一两天后的早晨醒来,发现没有发送电子邮件。

任何帮助将不胜感激:)

3 个答案:

答案 0 :(得分:9)

我会说出许多其他更适合做这种方法的评论,但我相信你的问题与以下几行有关:

Console.Read();

来自文档:

  

当您键入输入字符时,Read方法会阻止其返回;它   按Enter键时终止。

因此它将阻止等待永远不会到来的条目。

答案 1 :(得分:0)

保留一个时间变量,表示"下一步"要运行的日期时间。

在你的循环中,只需检查当前时间并运行你的代码..然后将变量重置为下一个白天,即现在+ 24小时。

另一个答案表明问题在于:

Console.Read();

需要删除

答案 2 :(得分:0)

如果您真的希望在不使用计时器或现有调度程序设施的情况下手动执行此操作,我建议您更严格并自己构建一个简单的任务计划程序类。你需要的部分:

  • 用于存储每个任务的类,其中包括要为任务执行的代码以及每个任务应运行的时间表。
  • 此类任务的列表
  • 计算下一个截止日期何时来自您的任务列表的方法,以便您知道要睡多长时间。
  • SemaphoreSlim要睡觉(而不是Thread.Sleep()
    • 使用SemaphoreSlim,因为如果信号量永远不会释放,它会通过传递等待时间来充当Thread.Sleep();但也因为如果您的调度程序确定已添加新任务并且应该唤醒它以重新评估下一个截止日期,您可以手动释放它。

我建议将您的截止日期存储在UTC中,并且使用UTC时间进行大部分时间计算工作,这样就不会出现有关时区变化或DST的混淆。

在下一个截止日期之前,您还应该考虑不只是整个时间都在睡觉,以防万一有更新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 );
    }
}