/// <summary> /// Returns a list of Dates that are the next fire times of a /// <see cref="ITrigger" />. /// The input trigger will be cloned before any work is done, so you need /// not worry about its state being altered by this method. /// </summary> /// <param name="trigg">The trigger upon which to do the work</param> /// <param name="cal">The calendar to apply to the trigger's schedule</param> /// <param name="numTimes">The number of next fire times to produce</param> public static IReadOnlyList <DateTimeOffset> ComputeFireTimes(IOperableTrigger trigg, ICalendar?cal, int numTimes) { List <DateTimeOffset> lst = new List <DateTimeOffset>(); IOperableTrigger t = (IOperableTrigger)trigg.Clone(); if (t.GetNextFireTimeUtc() == null || !t.GetNextFireTimeUtc().HasValue) { t.ComputeFirstFireTimeUtc(cal); } for (int i = 0; i < numTimes; i++) { DateTimeOffset?d = t.GetNextFireTimeUtc(); if (d.HasValue) { lst.Add(d.Value); t.Triggered(cal); } else { break; } } return(lst.AsReadOnly()); }
/// <summary> /// Returns a list of Dates that are the next fire times of a <see cref="ITrigger" /> /// that fall within the given date range. The input trigger will be cloned /// before any work is done, so you need not worry about its state being /// altered by this method. /// <para> /// NOTE: if this is a trigger that has previously fired within the given /// date range, then firings which have already occurred will not be listed /// in the output List. /// </para> /// </summary> /// <param name="trigg">The trigger upon which to do the work</param> /// <param name="cal">The calendar to apply to the trigger's schedule</param> /// <param name="from">The starting date at which to find fire times</param> /// <param name="to">The ending date at which to stop finding fire times</param> public static IReadOnlyList <DateTimeOffset> ComputeFireTimesBetween(IOperableTrigger trigg, ICalendar?cal, DateTimeOffset from, DateTimeOffset to) { List <DateTimeOffset> lst = new List <DateTimeOffset>(); IOperableTrigger t = (IOperableTrigger)trigg.Clone(); if (t.GetNextFireTimeUtc() == null || !t.GetNextFireTimeUtc().HasValue) { t.StartTimeUtc = from; t.EndTimeUtc = to; t.ComputeFirstFireTimeUtc(cal); } // TODO: this method could be more efficient by using logic specific // to the type of trigger ... while (true) { DateTimeOffset?d = t.GetNextFireTimeUtc(); if (d.HasValue) { if (d.Value < from) { t.Triggered(cal); continue; } if (d.Value > to) { break; } lst.Add(d.Value); t.Triggered(cal); } else { break; } } return(lst.AsReadOnly()); }
// Adapted from https://github.com/quartznet/quartznet/blob/master/src/Quartz/TriggerUtils.cs public static int ComputeFireTimeCountBetween(IOperableTrigger trigg, ICalendar cal, DateTimeOffset from, DateTimeOffset to) { int count = 0; IOperableTrigger t = (IOperableTrigger)trigg.Clone(); if (t.GetNextFireTimeUtc() == null || !t.GetNextFireTimeUtc().HasValue) { t.StartTimeUtc = from; t.EndTimeUtc = to; t.ComputeFirstFireTimeUtc(cal); } // TODO: this method could be more efficient by using logic specific // to the type of trigger ... while (true) { DateTimeOffset?d = t.GetNextFireTimeUtc(); if (d.HasValue) { if (d.Value < from) { t.Triggered(cal); continue; } if (d.Value > to) { break; } count++; t.Triggered(cal); } else { break; } } return(count); }
/// <summary> /// Compute the <see cref="DateTimeOffset" /> that is 1 second after the Nth firing of /// the given <see cref="ITrigger" />, taking the trigger's associated /// <see cref="ICalendar" /> into consideration. /// </summary> /// <remarks> /// The input trigger will be cloned before any work is done, so you need /// not worry about its state being altered by this method. /// </remarks> /// <param name="trigger">The trigger upon which to do the work</param> /// <param name="calendar">The calendar to apply to the trigger's schedule</param> /// <param name="numberOfTimes">The number of next fire times to produce</param> /// <returns>the computed Date, or null if the trigger (as configured) will not fire that many times</returns> public static DateTimeOffset?ComputeEndTimeToAllowParticularNumberOfFirings(IOperableTrigger trigger, ICalendar?calendar, int numberOfTimes) { IOperableTrigger t = (IOperableTrigger)trigger.Clone(); if (t.GetNextFireTimeUtc() == null) { t.ComputeFirstFireTimeUtc(calendar); } int c = 0; DateTimeOffset?endTime = null; for (int i = 0; i < numberOfTimes; i++) { DateTimeOffset?d = t.GetNextFireTimeUtc(); if (d != null) { c++; t.Triggered(calendar); if (c == numberOfTimes) { endTime = d; } } else { break; } } if (endTime == null) { return(null); } endTime = endTime.Value.AddSeconds(1); return(endTime); }
protected virtual TriggerFiredBundle TriggerFired(ConnectionAndTransactionHolder conn, IOperableTrigger trigger) { IJobDetail job; ICalendar cal = null; // Make sure trigger wasn't deleted, paused, or completed... try { // if trigger was deleted, state will be StateDeleted string state = Delegate.SelectTriggerState(conn, trigger.Key); if (!state.Equals(StateAcquired)) { return null; } } catch (Exception e) { throw new JobPersistenceException("Couldn't select trigger state: " + e.Message, e); } try { job = RetrieveJob(conn, trigger.JobKey); if (job == null) { return null; } } catch (JobPersistenceException jpe) { try { Log.Error("Error retrieving job, setting trigger state to ERROR.", jpe); Delegate.UpdateTriggerState(conn, trigger.Key, StateError); } catch (Exception sqle) { Log.Error("Unable to set trigger state to ERROR.", sqle); } throw; } if (trigger.CalendarName != null) { cal = RetrieveCalendar(conn, trigger.CalendarName); if (cal == null) { return null; } } try { Delegate.UpdateFiredTrigger(conn, trigger, StateExecuting, job); } catch (Exception e) { throw new JobPersistenceException("Couldn't insert fired trigger: " + e.Message, e); } DateTimeOffset? prevFireTime = trigger.GetPreviousFireTimeUtc(); // call triggered - to update the trigger's next-fire-time state... trigger.Triggered(cal); string state2 = StateWaiting; bool force = true; if (job.ConcurrentExecutionDisallowed) { state2 = StateBlocked; force = false; try { Delegate.UpdateTriggerStatesForJobFromOtherState(conn, job.Key, StateBlocked, StateWaiting); Delegate.UpdateTriggerStatesForJobFromOtherState(conn, job.Key, StateBlocked, StateAcquired); Delegate.UpdateTriggerStatesForJobFromOtherState(conn, job.Key, StatePausedBlocked, StatePaused); } catch (Exception e) { throw new JobPersistenceException("Couldn't update states of blocked triggers: " + e.Message, e); } } if (!trigger.GetNextFireTimeUtc().HasValue) { state2 = StateComplete; force = true; } StoreTrigger(conn, trigger, job, true, state2, force, false); job.JobDataMap.ClearDirtyFlag(); return new TriggerFiredBundle( job, trigger, cal, trigger.Key.Group.Equals(SchedulerConstants.DefaultRecoveryGroup), SystemTime.UtcNow(), trigger.GetPreviousFireTimeUtc(), prevFireTime, trigger.GetNextFireTimeUtc()); }