Mercurial > servermonitor
view ServerMonitor/Objects/Schedule.cs @ 17:68d7834dc28e
More comments.
author | Brad Greco <brad@bgreco.net> |
---|---|
date | Sat, 25 May 2019 15:14:26 -0400 |
parents | d92176c5398a |
children | 2342e9459444 |
line wrap: on
line source
using System; namespace ServerMonitorApp { /// <summary>Schedule to control when a check is automatically executed.<summary> public class Schedule { // Required empty constructor for XML serialization. public Schedule() { } /// <summary>Schedule constructor</summary> /// <param name="units">The time units to use.</param> /// <param name="frequency">How frequently to run the check.</param> /// <param name="startTime">Time of day the check should begin running.</param> /// <param name="endTime">Time of day the check should stop running.</param> /// <remarks> /// If endTime is before startTime, then the endTime is interpreted as being on the next day. /// For example, if startTime = 17:00 and endTime is 8:00, then the check will start running /// at 17:00 and stop running at 8:00 the next day. /// </remarks> public Schedule(FrequencyUnits units, int frequency, TimeSpan startTime, TimeSpan endTime) { Units = units; Frequency = frequency; StartTime = startTime; EndTime = endTime; } /// <summary>How often the check should be executed.</summary> public int Frequency { get; set; } /// <summary>The time units used to interpret the frequency.</summary> public FrequencyUnits Units { get; set; } /// <summary>Time of day the check should begin running.</summary> public TimeSpan StartTime { get; set; } /// <summary>Time of day the check should stop running.</summary> public TimeSpan EndTime { get; set; } /// <summary>Given the last time a check was scheduled to run, calculates the next time in the future it should run.</summary> /// <param name="lastScheduledTime">The last time a check was scheduled to run.</param> public DateTime GetNextTime(DateTime lastScheduledTime) { return GetNextTime(lastScheduledTime, DateTime.Now); } /// <summary>Given the last time a check was scheduled to run, calculates the next time after the given date it should run.</summary> /// <param name="lastScheduledTime">The last time a check was scheduled to run.</param> /// <param name="minStartTime">The earliest allowed time to return.</param> /// <remarks> /// The next execution time of a check cannot necessarily be determined by taking the /// last execution time and adding the configured number of time units. The computer might /// have been asleep or the program might have not been running, so the next date might /// be in the past. /// /// To best follow the schedule, we take the last execution time and fast-forward time /// by adding the configured time interval until we get a resulting time that is in the future. /// For example, suppose a check is scheduled to run every 5 minutes starting at 7:00. /// The check last ran at 7:40, and the computer was suspended shortly thereafter and resumed /// at 8:28. The next execution time is determined by adding 5 minutes to 7:40 until we obtain /// a time after 8:28, in this case, 8:30. /// </remarks> public DateTime GetNextTime(DateTime lastScheduledTime, DateTime minStartTime) { // Start by setting the next time to the last time the check was run. DateTime nextTime = lastScheduledTime; if (Units == FrequencyUnits.Day) { // If the check is scheduled only once a day, simply add days until we find a time in the future. while (nextTime < minStartTime) nextTime = nextTime.AddDays(Frequency).Date.Add(StartTime); } else { // If the last run time was more than a day ago, fast-forward a day at a time to reduce the number of loops. if (nextTime < minStartTime.AddHours(-24)) nextTime = minStartTime.Date.Add(StartTime).AddHours(-24); // Add the configured time interval to the last run time until we obtain a time in the future. while (nextTime < minStartTime) { switch (Units) { case FrequencyUnits.Second: nextTime = nextTime.AddSeconds(Frequency); break; case FrequencyUnits.Minute: nextTime = nextTime.AddMinutes(Frequency); break; case FrequencyUnits.Hour: nextTime = nextTime.AddHours(Frequency); break; default: throw new InvalidOperationException("Unexpected frequency units: " + Units); } } // Now we have the next date and time, but we don't know yet if it is within // the active times of day the check is allowed to run between. if (StartTime < EndTime) { // The allowed start and end times are on the same day. // If the next scheduled time is too early (before the allowed start time), // wait to run it until the start time happens. if (nextTime.TimeOfDay < StartTime) nextTime = nextTime.Date + StartTime; // If the next scheduled time is too late (after the allowed end time), // wait to run it until the start time happens on the following day. else if (nextTime.TimeOfDay > EndTime) nextTime = nextTime.Date.AddDays(1) + StartTime; } else if (nextTime.TimeOfDay > EndTime && nextTime.TimeOfDay < StartTime) { // The allowed start time is on the day after the allowed end time, // and the next scheduled time is too early (before the allowed start time). // Wait to run the check until the allowed start time happens. nextTime = nextTime.Date + StartTime; } } return nextTime; } public override string ToString() { return string.Format("Every {0} {1}", Frequency, Units.ToString().ToLower() + (Frequency == 1 ? "" : "s")); } } /// <summary>Units of time that a check can be scheduled to run in intervals of.</summary> public enum FrequencyUnits { Second, Minute, Hour, Day } }