예제 #1
0
        /// <summary>
        /// Checks whether the schedule is currently past due.
        /// </summary>
        /// <remarks>
        /// On startup, all schedules are checked to see if they are past due. Any
        /// timers that are past due will be executed immediately by default. Subclasses can
        /// change this behavior by inspecting the current time and schedule to determine
        /// whether it should be considered past due.
        /// </remarks>
        /// <param name="timerName">The name of the timer to check.</param>
        /// <param name="now">The time to check.</param>
        /// <param name="schedule">The <see cref="TimerSchedule"/></param>
        /// <param name="lastStatus">The last recorded status, or null if the status has never been recorded.</param>
        /// <returns>A non-zero <see cref="TimeSpan"/> if the schedule is past due, otherwise <see cref="TimeSpan.Zero"/>.</returns>
        public virtual async Task <TimeSpan> CheckPastDueAsync(string timerName, DateTime now, TimerSchedule schedule, ScheduleStatus lastStatus)
        {
            DateTime recordedNextOccurrence;

            if (lastStatus == null)
            {
                // If we've never recorded a status for this timer, write an initial
                // status entry. This ensures that for a new timer, we've captured a
                // status log for the next occurrence even though no occurrence has happened yet
                // (ensuring we don't miss an occurrence)
                DateTime nextOccurrence = schedule.GetNextOccurrence(now);
                lastStatus = new ScheduleStatus
                {
                    Last = default(DateTime),
                    Next = nextOccurrence
                };
                await UpdateStatusAsync(timerName, lastStatus);

                recordedNextOccurrence = nextOccurrence;
            }
            else
            {
                // ensure that the schedule hasn't been updated since the last
                // time we checked, and if it has, update the status
                DateTime expectedNextOccurrence;
                if (lastStatus.Last == default(DateTime))
                {
                    // there have been no executions of the function yet, so compute
                    // from now
                    expectedNextOccurrence = schedule.GetNextOccurrence(now);
                }
                else
                {
                    // compute the next occurrence from the last
                    expectedNextOccurrence = schedule.GetNextOccurrence(lastStatus.Last);
                }

                if (lastStatus.Next != expectedNextOccurrence)
                {
                    lastStatus.Next = expectedNextOccurrence;
                    await UpdateStatusAsync(timerName, lastStatus);
                }
                recordedNextOccurrence = lastStatus.Next;
            }

            if (now > recordedNextOccurrence)
            {
                // if now is after the last next occurrence we recorded, we know we've missed
                // at least one schedule instance and we are past due
                return(now - recordedNextOccurrence);
            }
            else
            {
                // not past due
                return(TimeSpan.Zero);
            }
        }
        /// <summary>
        /// Checks whether the schedule is currently past due.
        /// </summary>
        /// <remarks>
        /// On startup, all schedules are checked to see if they are past due. Any
        /// timers that are past due will be executed immediately by default. Subclasses can
        /// change this behavior by inspecting the current time and schedule to determine
        /// whether it should be considered past due.
        /// </remarks>
        /// <param name="timerName">The name of the timer to check.</param>
        /// <param name="now">The time to check.</param>
        /// <param name="schedule">The <see cref="TimerSchedule"/></param>
        /// <param name="lastStatus">The last recorded status, or null if the status has never been recorded.</param>
        /// <returns>A non-zero <see cref="TimeSpan"/> if the schedule is past due, otherwise <see cref="TimeSpan.Zero"/>.</returns>
        public virtual async Task<TimeSpan> CheckPastDueAsync(string timerName, DateTime now, TimerSchedule schedule, ScheduleStatus lastStatus)
        {
            DateTime recordedNextOccurrence;
            if (lastStatus == null)
            {
                // If we've never recorded a status for this timer, write an initial
                // status entry. This ensures that for a new timer, we've captured a
                // status log for the next occurrence even though no occurrence has happened yet
                // (ensuring we don't miss an occurrence)
                DateTime nextOccurrence = schedule.GetNextOccurrence(now);
                lastStatus = new ScheduleStatus
                {
                    Last = default(DateTime),
                    Next = nextOccurrence
                };
                await UpdateStatusAsync(timerName, lastStatus);
                recordedNextOccurrence = nextOccurrence;
            }
            else
            {
                // ensure that the schedule hasn't been updated since the last
                // time we checked, and if it has, update the status
                DateTime expectedNextOccurrence;
                if (lastStatus.Last == default(DateTime))
                {
                    // there have been no executions of the function yet, so compute
                    // from now
                    expectedNextOccurrence = schedule.GetNextOccurrence(now);
                }
                else
                {
                    // compute the next occurrence from the last
                    expectedNextOccurrence = schedule.GetNextOccurrence(lastStatus.Last);
                }

                if (lastStatus.Next != expectedNextOccurrence)
                {
                    lastStatus.Next = expectedNextOccurrence;
                    await UpdateStatusAsync(timerName, lastStatus);
                }
                recordedNextOccurrence = lastStatus.Next;
            }

            if (now > recordedNextOccurrence)
            {
                // if now is after the last next occurrence we recorded, we know we've missed
                // at least one schedule instance and we are past due
                return now - recordedNextOccurrence;
            }
            else
            {
                // not past due
                return TimeSpan.Zero;
            }
        }
        /// <summary>
        /// Returns the <see cref="TimeSpan"/> duration that the specified timer is past due.
        /// </summary>
        /// <param name="timerName">The name of the timer.</param>
        /// <param name="now">The current time.</param>
        /// <param name="schedule">The <see cref="TimerSchedule"/>.</param>
        /// <returns>The duration the timer is past due.</returns>
        protected async Task<TimeSpan> GetPastDueDuration(string timerName, DateTime now, TimerSchedule schedule)
        {
            StatusEntry status = GetStatus(timerName);
            DateTime recordedNextOccurrence;
            if (status == null)
            {
                // If we've never recorded a status for this timer, write an initial
                // status entry. This ensures that for a new timer, we've captured a
                // status log for the next occurrence even though no occurrence has happened yet
                // (ensuring we don't miss an occurrence)
                DateTime nextOccurrence = schedule.GetNextOccurrence(now);
                await UpdateAsync(timerName, default(DateTime), nextOccurrence);
                recordedNextOccurrence = nextOccurrence;
            }
            else
            {
                // ensure that the schedule hasn't been updated since the last
                // time we checked, and if it has, update the status file
                DateTime expectedNextOccurrence = schedule.GetNextOccurrence(status.Last);
                if (status.Next != expectedNextOccurrence)
                {
                    await UpdateAsync(timerName, status.Last, expectedNextOccurrence);
                }
                recordedNextOccurrence = status.Next;
            }

            if (now > recordedNextOccurrence)
            {
                // if now is after the last next occurrence we recorded, we know we've missed
                // at least one schedule instance and we are past due
                return now - recordedNextOccurrence;
            }
            else
            {
                // not past due
                return TimeSpan.Zero;
            }   
        }
        /// <summary>
        /// Checks whether the schedule is currently past due.
        /// </summary>
        /// <remarks>
        /// On startup, all schedules are checked to see if they are past due. Any
        /// timers that are past due will be executed immediately by default. Subclasses can
        /// change this behavior by inspecting the current time and schedule to determine
        /// whether it should be considered past due.
        /// </remarks>
        /// <param name="timerName">The name of the timer to check.</param>
        /// <param name="now">The time to check.</param>
        /// <param name="schedule">The <see cref="TimerSchedule"/>.</param>
        /// <param name="lastStatus">The last recorded status, or null if the status has never been recorded.</param>
        /// <returns>A non-zero <see cref="TimeSpan"/> if the schedule is past due, otherwise <see cref="TimeSpan.Zero"/>.</returns>
        public virtual async Task <TimeSpan> CheckPastDueAsync(string timerName, DateTime now, TimerSchedule schedule, ScheduleStatus lastStatus)
        {
            DateTime recordedNextOccurrence;

            if (lastStatus == null)
            {
                // If we've never recorded a status for this timer, write an initial
                // status entry. This ensures that for a new timer, we've captured a
                // status log for the next occurrence even though no occurrence has happened yet
                // (ensuring we don't miss an occurrence)
                DateTime nextOccurrence = schedule.GetNextOccurrence(now);
                lastStatus = new ScheduleStatus
                {
                    Last        = default(DateTime),
                    Next        = nextOccurrence,
                    LastUpdated = now
                };
                await UpdateStatusAsync(timerName, lastStatus);

                recordedNextOccurrence = nextOccurrence;
            }
            else
            {
                DateTime expectedNextOccurrence;

                // Track the time that was used to create 'expectedNextOccurrence'.
                DateTime lastUpdated;

                if (lastStatus.Last != default(DateTime))
                {
                    // If we have a 'Last' value, we know that we used this to calculate 'Next'
                    // in a previous invocation.
                    expectedNextOccurrence = schedule.GetNextOccurrence(lastStatus.Last);
                    lastUpdated            = lastStatus.Last;
                }
                else if (lastStatus.LastUpdated != default(DateTime))
                {
                    // If the trigger has never fired, we won't have 'Last', but we will have
                    // 'LastUpdated', which tells us the last time that we used to calculate 'Next'.
                    expectedNextOccurrence = schedule.GetNextOccurrence(lastStatus.LastUpdated);
                    lastUpdated            = lastStatus.LastUpdated;
                }
                else
                {
                    // If we do not have 'LastUpdated' or 'Last', we don't have enough information to
                    // properly calculate 'Next', so we'll calculate it from the current time.
                    expectedNextOccurrence = schedule.GetNextOccurrence(now);
                    lastUpdated            = now;
                }

                // ensure that the schedule hasn't been updated since the last
                // time we checked, and if it has, update the status to use the new schedule
                if (lastStatus.Next != expectedNextOccurrence)
                {
                    // if the schedule has changed and the next occurrence is in the past,
                    // recalculate it based on the current time as we don't want it to register
                    // immediately as 'past due'.
                    if (now > expectedNextOccurrence)
                    {
                        expectedNextOccurrence = schedule.GetNextOccurrence(now);
                        lastUpdated            = now;
                    }

                    lastStatus.Last        = default(DateTime);
                    lastStatus.Next        = expectedNextOccurrence;
                    lastStatus.LastUpdated = lastUpdated;
                    await UpdateStatusAsync(timerName, lastStatus);
                }
                recordedNextOccurrence = lastStatus.Next;
            }

            if (now > recordedNextOccurrence)
            {
                // if now is after the last next occurrence we recorded, we know we've missed
                // at least one schedule instance and we are past due
                return(now - recordedNextOccurrence);
            }
            else
            {
                // not past due
                return(TimeSpan.Zero);
            }
        }