Beispiel #1
0
        internal static TimerSchedule Create(TimerTriggerAttribute attribute, INameResolver nameResolver)
        {
            TimerSchedule schedule = null;

            if (!string.IsNullOrEmpty(attribute.ScheduleExpression))
            {
                string resolvedExpression = nameResolver.ResolveWholeString(attribute.ScheduleExpression);

                CronSchedule cronSchedule = null;
                if (CronSchedule.TryCreate(resolvedExpression, out cronSchedule))
                {
                    schedule = cronSchedule;

                    DateTime[] nextOccurrences = cronSchedule.InnerSchedule.GetNextOccurrences(DateTime.Now, DateTime.Now + TimeSpan.FromMinutes(1)).ToArray();
                    if (nextOccurrences.Length > 1)
                    {
                        // if there is more than one occurrence due in the next minute,
                        // assume that this is a sub-minute constant schedule and disable
                        // persistence
                        attribute.UseMonitor = false;
                    }
                    else if (!attribute.UseMonitor.HasValue)
                    {
                        // if the user hasn't specified a value
                        // set to true
                        attribute.UseMonitor = true;
                    }
                }
                else
                {
                    TimeSpan periodTimespan = TimeSpan.Parse(resolvedExpression);
                    schedule = new ConstantSchedule(periodTimespan);

                    if (periodTimespan.TotalMinutes < 1)
                    {
                        // for very frequent constant schedules, we want to disable persistence
                        attribute.UseMonitor = false;
                    }
                    else if (!attribute.UseMonitor.HasValue)
                    {
                        // if the user hasn't specified a value
                        // set to true
                        attribute.UseMonitor = true;
                    }
                }
            }
            else
            {
                schedule = (TimerSchedule)Activator.CreateInstance(attribute.ScheduleType);
                if (!attribute.UseMonitor.HasValue)
                {
                    // if the user hasn't specified a value
                    // set to true
                    attribute.UseMonitor = true;
                }
            }

            return(schedule);
        }
        /// <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;
            }
        }
        internal static string FormatNextOccurrences(TimerSchedule schedule, int count, DateTime? now = null)
        {
            if (schedule == null)
            {
                throw new ArgumentNullException("schedule");
            }

            IEnumerable<DateTime> nextOccurrences = schedule.GetNextOccurrences(count, now);
            StringBuilder builder = new StringBuilder();
            builder.AppendLine(string.Format("The next {0} occurrences of the schedule will be:", count));
            foreach (DateTime occurrence in nextOccurrences)
            {
                builder.AppendLine(occurrence.ToString());
            }

            return builder.ToString();
        }
Beispiel #4
0
        internal static TimerSchedule Create(TimerTriggerAttribute attribute, INameResolver nameResolver)
        {
            TimerSchedule schedule = null;

            if (!string.IsNullOrEmpty(attribute.ScheduleExpression))
            {
                string resolvedExpression = nameResolver.ResolveWholeString(attribute.ScheduleExpression);

                CronSchedule cronSchedule = null;
                TimeSpan     periodTimespan;
                if (CronSchedule.TryCreate(resolvedExpression, out cronSchedule))
                {
                    schedule = cronSchedule;

                    DateTime[] nextOccurrences = cronSchedule.InnerSchedule.GetNextOccurrences(DateTime.Now, DateTime.Now + TimeSpan.FromMinutes(1)).ToArray();
                    if (nextOccurrences.Length > 1)
                    {
                        // if there is more than one occurrence due in the next minute,
                        // assume that this is a sub-minute constant schedule and disable
                        // persistence
                        attribute.UseMonitor = false;
                    }
                }
                else if (TimeSpan.TryParse(resolvedExpression, out periodTimespan))
                {
                    schedule = new ConstantSchedule(periodTimespan);

                    if (periodTimespan.TotalMinutes < 1)
                    {
                        // for very frequent constant schedules, we want to disable persistence
                        attribute.UseMonitor = false;
                    }
                }
                else
                {
                    throw new ArgumentException("The schedule expression was not recognized as a valid cron expression or timespan string.");
                }
            }
            else
            {
                schedule = (TimerSchedule)Activator.CreateInstance(attribute.ScheduleType);
            }

            return(schedule);
        }
Beispiel #5
0
        internal static TimerSchedule Create(TimerTriggerAttribute attribute, INameResolver nameResolver, ILogger logger)
        {
            TimerSchedule schedule = null;

            if (!string.IsNullOrEmpty(attribute.ScheduleExpression))
            {
                string resolvedExpression = nameResolver.ResolveWholeString(attribute.ScheduleExpression);
                if (CronSchedule.TryCreate(resolvedExpression, out CronSchedule cronSchedule))
                {
                    schedule = cronSchedule;
                    if (attribute.UseMonitor && ShouldDisableScheduleMonitor(cronSchedule, DateTime.Now))
                    {
                        logger.LogDebug("UseMonitor changed to false based on schedule frequency.");
                        attribute.UseMonitor = false;
                    }
                }
                else if (TimeSpan.TryParse(resolvedExpression, out TimeSpan periodTimespan))
                {
                    schedule = new ConstantSchedule(periodTimespan);

                    if (attribute.UseMonitor && periodTimespan.TotalMinutes < 1)
                    {
                        // for very frequent constant schedules, we want to disable persistence
                        logger.LogDebug("UseMonitor changed to false based on schedule frequency.");
                        attribute.UseMonitor = false;
                    }
                }
                else
                {
                    throw new ArgumentException(string.Format("The schedule expression '{0}' was not recognized as a valid cron expression or timespan string.", resolvedExpression));
                }
            }
            else
            {
                schedule = (TimerSchedule)Activator.CreateInstance(attribute.ScheduleType);
            }

            return(schedule);
        }
 /// <inheritdoc/>
 public override async Task<bool> IsPastDueAsync(string timerName, DateTime now, TimerSchedule schedule)
 {
     TimeSpan pastDueDuration = await GetPastDueDuration(timerName, now, schedule);
     return pastDueDuration != 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;
            }   
        }
Beispiel #8
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,
                    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);
            }
        }
 /// <summary>
 /// Determines 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>
 /// <returns>True if the schedule is past due, false otherwise.</returns>
 public abstract Task <bool> IsPastDueAsync(string timerName, DateTime now, TimerSchedule schedule);
 /// <summary>
 /// Determines 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>
 /// <returns>True if the schedule is past due, false otherwise.</returns>
 public abstract Task<bool> IsPastDueAsync(string timerName, DateTime now, TimerSchedule schedule);
        /// <inheritdoc/>
        public override async Task <bool> IsPastDueAsync(string timerName, DateTime now, TimerSchedule schedule)
        {
            TimeSpan pastDueDuration = await GetPastDueDuration(timerName, now, schedule);

            return(pastDueDuration != TimeSpan.Zero);
        }
 /// <summary>
 /// Constructs a new instances
 /// </summary>
 /// <param name="schedule">The timer trigger schedule.</param>
 public TimerInfo(TimerSchedule schedule)
 {
     Schedule = schedule;
 }
 /// <summary>
 /// Constructs a new instance
 /// </summary>
 /// <param name="schedule">The timer trigger schedule.</param>
 /// <param name="status">The current schedule status.</param>
 /// <param name="isPastDue">True if the schedule is past due, false otherwise.</param>
 public TimerInfo(TimerSchedule schedule, ScheduleStatus status, bool isPastDue = false)
 {
     Schedule = schedule;
     ScheduleStatus = status;
     IsPastDue = isPastDue;
 }