public virtual async Task CheckPastDueAsync()

in src/WebJobs.Extensions/Extensions/Timers/Scheduling/ScheduleMonitor.cs [81:161]


        public virtual async Task<TimeSpan> CheckPastDueAsync(string timerName, DateTimeOffset now, TimerSchedule schedule, ScheduleStatus lastStatus)
        {
            DateTimeOffset 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)
                DateTimeOffset nextOccurrence = schedule.GetNextOccurrence(now.LocalDateTime);
                lastStatus = new ScheduleStatus
                {
                    Last = DefaultDateTime,
                    Next = nextOccurrence.LocalDateTime,
                    LastUpdated = now.LocalDateTime
                };
                await UpdateStatusAsync(timerName, lastStatus);
                recordedNextOccurrence = nextOccurrence;
            }
            else
            {
                DateTimeOffset expectedNextOccurrence;

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

                if (lastStatus.Last > DefaultDateTimeThreshold)
                {
                    // 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 > DefaultDateTimeThreshold)
                {
                    // 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.LocalDateTime);
                    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.LocalDateTime);
                        lastUpdated = now;
                    }

                    lastStatus.Last = DefaultDateTime;
                    lastStatus.Next = expectedNextOccurrence.LocalDateTime;
                    lastStatus.LastUpdated = lastUpdated.LocalDateTime;
                    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;
            }
        }