예제 #1
0
        /// <summary>
        /// Get a handle to the next trigger to be fired, and mark it as 'reserved'
        /// by the calling scheduler.
        /// </summary>
        /// <seealso cref="ITrigger" />
        public virtual IList<IOperableTrigger> AcquireNextTriggers(DateTimeOffset noLaterThan, int maxCount, TimeSpan timeWindow)
        {
            lock (lockObject)
            {
                // multiple instances management
                this.Schedulers.Save(new BsonDocument(
                    new BsonElement("_id", this.instanceId),
                    new BsonElement("Expires", (SystemTime.Now() + new TimeSpan(0, 10, 0)).UtcDateTime),
                    new BsonElement("State", "Running")));

                this.Schedulers.Remove(
                    Query.LT("Expires", SystemTime.Now().UtcDateTime));

                IEnumerable<BsonValue> activeInstances = this.Schedulers.Distinct("_id");

                this.Triggers.Update(
                    Query.NotIn("SchedulerInstanceId", activeInstances),
                    Update.Unset("SchedulerInstanceId")
                        .Set("State", "Waiting"));

                List<IOperableTrigger> result = new List<IOperableTrigger>();
                Collection.ISet<JobKey> acquiredJobKeysForNoConcurrentExec = new Collection.HashSet<JobKey>();
                DateTimeOffset? firstAcquiredTriggerFireTime = null;

                var candidates = this.Triggers.FindAs<Spi.IOperableTrigger>(
                    Query.And(
                        Query.EQ("State", "Waiting"),
                        Query.LTE("nextFireTimeUtc", (noLaterThan + timeWindow).UtcDateTime)))
                    .OrderBy(t => t.GetNextFireTimeUtc()).ThenByDescending(t => t.Priority);

                foreach (IOperableTrigger trigger in candidates)
                {
                    if (trigger.GetNextFireTimeUtc() == null)
                    {
                        continue;
                    }

                    // it's possible that we've selected triggers way outside of the max fire ahead time for batches
                    // (up to idleWaitTime + fireAheadTime) so we need to make sure not to include such triggers.
                    // So we select from the first next trigger to fire up until the max fire ahead time after that...
                    // which will perfectly honor the fireAheadTime window because the no firing will occur until
                    // the first acquired trigger's fire time arrives.
                    if (firstAcquiredTriggerFireTime != null
                        && trigger.GetNextFireTimeUtc() > (firstAcquiredTriggerFireTime.Value + timeWindow))
                    {
                        break;
                    }

                    if (this.ApplyMisfire(trigger))
                    {
                        if (trigger.GetNextFireTimeUtc() == null
                            || trigger.GetNextFireTimeUtc() > noLaterThan + timeWindow)
                        {
                            continue;
                        }
                    }

                    // If trigger's job is set as @DisallowConcurrentExecution, and it has already been added to result, then
                    // put it back into the timeTriggers set and continue to search for next trigger.
                    JobKey jobKey = trigger.JobKey;
                    IJobDetail job = this.Jobs.FindOneByIdAs<IJobDetail>(jobKey.ToBsonDocument());

                    if (job.ConcurrentExecutionDisallowed)
                    {
                        if (acquiredJobKeysForNoConcurrentExec.Contains(jobKey))
                        {
                            continue; // go to next trigger in store.
                        }
                        else
                        {
                            acquiredJobKeysForNoConcurrentExec.Add(jobKey);
                        }
                    }

                    trigger.FireInstanceId = this.GetFiredTriggerRecordId();
                    var acquired = this.Triggers.FindAndModify(
                        Query.And(
                            Query.EQ("_id", trigger.Key.ToBsonDocument()),
                            Query.EQ("State", "Waiting")),
                        SortBy.Null,
                        Update.Set("State", "Acquired")
                            .Set("SchedulerInstanceId", this.instanceId)
                            .Set("FireInstanceId", trigger.FireInstanceId));

                    if (acquired.ModifiedDocument != null)
                    {
                        result.Add(trigger);

                        if (firstAcquiredTriggerFireTime == null)
                        {
                            firstAcquiredTriggerFireTime = trigger.GetNextFireTimeUtc();
                        }
                    }

                    if (result.Count == maxCount)
                    {
                        break;
                    }
                }

                return result;
            }
        }
예제 #2
0
        /// <summary>
        /// Gets the property groups.
        /// </summary>
        /// <param name="prefix">The prefix.</param>
        /// <returns></returns>
        public virtual IList<string> GetPropertyGroups(string prefix)
        {
            var groups = new Collection.HashSet<string>();

            if (!prefix.EndsWith("."))
            {
                prefix += ".";
            }

            foreach (string key in props.Keys)
            {
                if (key.StartsWith(prefix))
                {
                    string groupName = key.Substring(prefix.Length, (key.IndexOf('.', prefix.Length)) - (prefix.Length));
                    groups.Add(groupName);
                }
            }

            return new List<string>(groups);
        }
예제 #3
0
        /// <summary>
        /// Resume (un-pause) all of the <see cref="IJobDetail" />s
        /// in the given group.
        /// <para>
        /// If any of the <see cref="IJob" /> s had <see cref="ITrigger" /> s that
        /// missed one or more fire-times, then the <see cref="ITrigger" />'s
        /// misfire instruction will be applied.
        /// </para>
        /// </summary>
        public virtual Collection.ISet<string> ResumeJobs(GroupMatcher<JobKey> matcher)
        {
            Collection.ISet<string> resumedGroups = new Collection.HashSet<string>();
            lock (lockObject)
            {
                Collection.ISet<JobKey> keys = GetJobKeys(matcher);

                foreach (string pausedJobGroup in this.PausedJobGroups.FindAllAs<string>())
                {
                    if (matcher.CompareWithOperator.Evaluate(pausedJobGroup, matcher.CompareToValue))
                    {
                        resumedGroups.Add(pausedJobGroup);
                    }
                }

                this.PausedTriggerGroups.Remove(
                        Query.All("_id", new BsonArray(resumedGroups)));

                foreach (JobKey key in keys)
                {
                    IList<IOperableTrigger> triggers = GetTriggersForJob(key);
                    foreach (IOperableTrigger trigger in triggers)
                    {
                        ResumeTrigger(trigger.Key);
                    }
                }
            }

            return resumedGroups;
        }
예제 #4
0
        /// <summary>
        /// Resume (un-pause) all of the <see cref="ITrigger" />s in the
        /// given group.
        /// <para>
        /// If any <see cref="ITrigger" /> missed one or more fire-times, then the
        /// <see cref="ITrigger" />'s misfire instruction will be applied.
        /// </para>
        /// </summary>
        public virtual IList<string> ResumeTriggers(GroupMatcher<TriggerKey> matcher)
        {
            Collection.ISet<string> groups = new Collection.HashSet<string>();
            lock (lockObject)
            {
                Collection.ISet<TriggerKey> keys = this.GetTriggerKeys(matcher);

                foreach (TriggerKey triggerKey in keys)
                {
                    groups.Add(triggerKey.Group);
                    IOperableTrigger trigger = this.Triggers.FindOneByIdAs<IOperableTrigger>(triggerKey.ToBsonDocument());
                    var pausedJobGroup = this.PausedJobGroups.FindOneByIdAs<string>(trigger.JobKey.Group);
                    if (pausedJobGroup != null)
                    {
                        continue;
                    }

                    this.ResumeTrigger(triggerKey);
                }

                foreach (String group in groups)
                {
                    this.PausedTriggerGroups.Remove(
                        Query.EQ("_id", group));
                }
            }

            return new List<string>(groups);
        }
예제 #5
0
        protected virtual void ClusterRecover(ConnectionAndTransactionHolder conn, IList<SchedulerStateRecord> failedInstances)
        {
            if (failedInstances.Count > 0)
            {
                long recoverIds = SystemTime.UtcNow().Ticks;

                LogWarnIfNonZero(failedInstances.Count,
                                 "ClusterManager: detected " + failedInstances.Count + " failed or restarted instances.");
                try
                {
                    foreach (SchedulerStateRecord rec in failedInstances)
                    {
                        Log.Info("ClusterManager: Scanning for instance \"" + rec.SchedulerInstanceId +
                                 "\"'s failed in-progress jobs.");

                        IList<FiredTriggerRecord> firedTriggerRecs =
                            Delegate.SelectInstancesFiredTriggerRecords(conn, rec.SchedulerInstanceId);

                        int acquiredCount = 0;
                        int recoveredCount = 0;
                        int otherCount = 0;

                        Collection.HashSet<TriggerKey> triggerKeys = new Collection.HashSet<TriggerKey>();

                        foreach (FiredTriggerRecord ftRec in firedTriggerRecs)
                        {
                            TriggerKey tKey = ftRec.TriggerKey;
                            JobKey jKey = ftRec.JobKey;

                            triggerKeys.Add(tKey);

                            // release blocked triggers..
                            if (ftRec.FireInstanceState.Equals(StateBlocked))
                            {
                                Delegate.UpdateTriggerStatesForJobFromOtherState(conn, jKey,
                                                                                 StateWaiting,
                                                                                 StateBlocked);
                            }
                            else if (ftRec.FireInstanceState.Equals(StatePausedBlocked))
                            {
                                Delegate.UpdateTriggerStatesForJobFromOtherState(conn, jKey,
                                                                                 StatePaused,
                                                                                 StatePausedBlocked);
                            }

                            // release acquired triggers..
                            if (ftRec.FireInstanceState.Equals(StateAcquired))
                            {
                                Delegate.UpdateTriggerStateFromOtherState(conn, tKey, StateWaiting, StateAcquired);
                                acquiredCount++;
                            }
                            else if (ftRec.JobRequestsRecovery)
                            {
                                // handle jobs marked for recovery that were not fully
                                // executed..
                                if (JobExists(conn, jKey))
                                {
                                    SimpleTriggerImpl rcvryTrig =
                                        new SimpleTriggerImpl(
                                            "recover_" + rec.SchedulerInstanceId + "_" + Convert.ToString(recoverIds++, CultureInfo.InvariantCulture),
                                            SchedulerConstants.DefaultRecoveryGroup, ftRec.FireTimestamp);

                                    rcvryTrig.JobName = jKey.Name;
                                    rcvryTrig.JobGroup = jKey.Group;
                                    rcvryTrig.MisfireInstruction = MisfireInstruction.SimpleTrigger.FireNow;
                                    rcvryTrig.Priority = ftRec.Priority;
                                    JobDataMap jd = Delegate.SelectTriggerJobDataMap(conn, tKey);
                                    jd.Put(SchedulerConstants.FailedJobOriginalTriggerName, tKey.Name);
                                    jd.Put(SchedulerConstants.FailedJobOriginalTriggerGroup, tKey.Group);
                                    jd.Put(SchedulerConstants.FailedJobOriginalTriggerFiretimeInMillisecoonds, Convert.ToString(ftRec.FireTimestamp, CultureInfo.InvariantCulture));
                                    rcvryTrig.JobDataMap = jd;

                                    rcvryTrig.ComputeFirstFireTimeUtc(null);
                                    StoreTrigger(conn, rcvryTrig, null, false, StateWaiting, false, true);
                                    recoveredCount++;
                                }
                                else
                                {
                                    Log.Warn("ClusterManager: failed job '" + jKey +
                                             "' no longer exists, cannot schedule recovery.");
                                    otherCount++;
                                }
                            }
                            else
                            {
                                otherCount++;
                            }

                            // free up stateful job's triggers
                            if (ftRec.JobDisallowsConcurrentExecution)
                            {
                                Delegate.UpdateTriggerStatesForJobFromOtherState(conn, jKey, StateWaiting, StateBlocked);
                                Delegate.UpdateTriggerStatesForJobFromOtherState(conn, jKey, StatePaused, StatePausedBlocked);
                            }
                        }

                        Delegate.DeleteFiredTriggers(conn, rec.SchedulerInstanceId);

                        // Check if any of the fired triggers we just deleted were the last fired trigger
                        // records of a COMPLETE trigger.
                        int completeCount = 0;
                        foreach (TriggerKey triggerKey in triggerKeys)
                        {
                            if (
                                Delegate.SelectTriggerState(conn, triggerKey).Equals(StateComplete))
                            {
                                IList<FiredTriggerRecord> firedTriggers = Delegate.SelectFiredTriggerRecords(conn, triggerKey.Name, triggerKey.Group);
                                if (firedTriggers.Count == 0)
                                {
                                    if (RemoveTrigger(conn, triggerKey))
                                    {
                                        completeCount++;
                                    }
                                }
                            }
                        }
                        LogWarnIfNonZero(acquiredCount,
                                         "ClusterManager: ......Freed " + acquiredCount + " acquired trigger(s).");
                        LogWarnIfNonZero(completeCount,
                                         "ClusterManager: ......Deleted " + completeCount + " complete triggers(s).");
                        LogWarnIfNonZero(recoveredCount,
                                         "ClusterManager: ......Scheduled " + recoveredCount +
                                         " recoverable job(s) for recovery.");
                        LogWarnIfNonZero(otherCount,
                                         "ClusterManager: ......Cleaned-up " + otherCount + " other failed job(s).");

                        if (rec.SchedulerInstanceId.Equals(InstanceId) == false)
                        {
                            Delegate.DeleteSchedulerState(conn, rec.SchedulerInstanceId);
                        }
                    }
                }
                catch (Exception e)
                {
                    throw new JobPersistenceException("Failure recovering jobs: " + e.Message, e);
                }
            }
        }
예제 #6
0
        /// <summary>
        /// Pause all of the <see cref="IJob" />s in the given
        /// group - by pausing all of their <see cref="ITrigger" />s.
        /// </summary>
        /// <seealso cref="ResumeJobs" />
        public virtual IList<string> PauseJobs(GroupMatcher<JobKey> matcher)
        {
            return (IList<string>)ExecuteInLock(LockTriggerAccess, conn =>
                {
                    Collection.ISet<string> groupNames = new Collection.HashSet<string>();
                    Collection.ISet<JobKey> jobNames = GetJobNames(conn, matcher);

                    foreach (JobKey jobKey in jobNames)
                    {
                        IList<IOperableTrigger> triggers = GetTriggersForJob(conn, jobKey);
                        foreach (IOperableTrigger trigger in triggers)
                        {
                            PauseTrigger(conn, trigger.Key);
                        }
                        groupNames.Add(jobKey.Group);
                    }

                    return new List<string>(groupNames);
                });
        }
예제 #7
0
        /// <summary>
        /// Resume (un-pause) all of the <see cref="ITrigger" />s
        /// in the given group.
        /// <para>
        /// If any <see cref="ITrigger" /> missed one or more fire-times, then the
        /// <see cref="ITrigger" />'s misfire instruction will be applied.
        /// </para>
        /// </summary>
        public virtual IList<string> ResumeTriggers(ConnectionAndTransactionHolder conn, GroupMatcher<TriggerKey> matcher)
        {
            try
            {
                Delegate.DeletePausedTriggerGroup(conn, matcher);
                Collection.HashSet<string> groups = new Collection.HashSet<string>();

                Collection.ISet<TriggerKey> keys = Delegate.SelectTriggersInGroup(conn, matcher);

                foreach (TriggerKey key in keys)
                {
                    ResumeTrigger(conn, key);
                    groups.Add(key.Group);
                }

                return new List<string>(groups);

                // TODO: find an efficient way to resume triggers (better than the
                // above)... logic below is broken because of
                // findTriggersToBeBlocked()
                /*
                * int res =
                * getDelegate().UpdateTriggerGroupStateFromOtherState(conn,
                * groupName, StateWaiting, StatePaused);
                *
                * if(res > 0) {
                *
                * long misfireTime = System.currentTimeMillis();
                * if(getMisfireThreshold() > 0) misfireTime -=
                * getMisfireThreshold();
                *
                * Key[] misfires =
                * getDelegate().SelectMisfiredTriggersInGroupInState(conn,
                * groupName, StateWaiting, misfireTime);
                *
                * List blockedTriggers = findTriggersToBeBlocked(conn,
                * groupName);
                *
                * Iterator itr = blockedTriggers.iterator(); while(itr.hasNext()) {
                * Key key = (Key)itr.next();
                * getDelegate().UpdateTriggerState(conn, key.getName(),
                * key.getGroup(), StateBlocked); }
                *
                * for(int i=0; i < misfires.length; i++) {               String
                * newState = StateWaiting;
                * if(blockedTriggers.contains(misfires[i])) newState =
                * StateBlocked; UpdateMisfiredTrigger(conn,
                * misfires[i].getName(), misfires[i].getGroup(), newState, true); } }
                */
            }
            catch (Exception e)
            {
                throw new JobPersistenceException("Couldn't pause trigger group '" + matcher + "': " + e.Message, e);
            }
        }
예제 #8
0
        // TODO: this really ought to return something like a FiredTriggerBundle,
        // so that the fireInstanceId doesn't have to be on the trigger...
        protected virtual IList<IOperableTrigger> AcquireNextTrigger(ConnectionAndTransactionHolder conn, DateTimeOffset noLaterThan, int maxCount, TimeSpan timeWindow)
        {
            List<IOperableTrigger> acquiredTriggers = new List<IOperableTrigger>();
            Collection.ISet<JobKey> acquiredJobKeysForNoConcurrentExec = new Collection.HashSet<JobKey>();
            const int MaxDoLoopRetry = 3;
            int currentLoopCount = 0;
            DateTimeOffset? firstAcquiredTriggerFireTime = null;

            do
            {
                currentLoopCount ++;
                try
                {
                    IList<TriggerKey> keys;

                    // If timeWindow is specified, then we need to select trigger fire time with wider range!
                    if (timeWindow > TimeSpan.Zero)
                    {
                        keys = Delegate.SelectTriggerToAcquire(conn, noLaterThan + timeWindow, MisfireTime, maxCount);
                    }
                    else
                    {
                        keys = Delegate.SelectTriggerToAcquire(conn, noLaterThan, MisfireTime, maxCount);
                    }

                    // No trigger is ready to fire yet.
                    if (keys == null || keys.Count == 0)
                    {
                        return acquiredTriggers;
                    }

                    foreach (TriggerKey triggerKey in keys)
                    {
                        // If our trigger is no longer available, try a new one.
                        IOperableTrigger nextTrigger = RetrieveTrigger(conn, triggerKey);
                        if (nextTrigger == null)
                        {
                            continue; // next trigger
                        }
                        // it's possible that we've selected triggers way outside of the max fire ahead time for batches
                        // (up to idleWaitTime + fireAheadTime) so we need to make sure not to include such triggers.
                        // So we select from the first next trigger to fire up until the max fire ahead time after that...
                        // which will perfectly honor the fireAheadTime window because the no firing will occur until
                        // the first acquired trigger's fire time arrives.
                        if (firstAcquiredTriggerFireTime != null && nextTrigger.GetNextFireTimeUtc() > (firstAcquiredTriggerFireTime.Value + timeWindow))
                        {
                            break;
                        }

                        // If trigger's job is set as @DisallowConcurrentExecution, and it has already been added to result, then
                        // put it back into the timeTriggers set and continue to search for next trigger.
                        JobKey jobKey = nextTrigger.JobKey;
                        IJobDetail job = Delegate.SelectJobDetail(conn, jobKey, TypeLoadHelper);
                        if (job.ConcurrentExecutionDisallowed)
                        {
                            if (acquiredJobKeysForNoConcurrentExec.Contains(jobKey))
                            {
                                continue; // next trigger
                            }
                            else
                            {
                                acquiredJobKeysForNoConcurrentExec.Add(jobKey);
                            }
                        }

                        // We now have a acquired trigger, let's add to return list.
                        // If our trigger was no longer in the expected state, try a new one.
                        int rowsUpdated = Delegate.UpdateTriggerStateFromOtherState(conn, triggerKey, StateAcquired, StateWaiting);
                        if (rowsUpdated <= 0)
                        {
                            // TODO: Hum... shouldn't we log a warning here?
                            continue; // next trigger
                        }
                        nextTrigger.FireInstanceId = GetFiredTriggerRecordId();
                        Delegate.InsertFiredTrigger(conn, nextTrigger, StateAcquired, null);

                        acquiredTriggers.Add(nextTrigger);
                        if (firstAcquiredTriggerFireTime == null)
                        {
                            firstAcquiredTriggerFireTime = nextTrigger.GetNextFireTimeUtc();
                        }
                    }

                    // if we didn't end up with any trigger to fire from that first
                    // batch, try again for another batch. We allow with a max retry count.
                    if (acquiredTriggers.Count == 0 && currentLoopCount < MaxDoLoopRetry)
                    {
                        continue;
                    }

                    // We are done with the while loop.
                    break;
                }
                catch (Exception e)
                {
                    throw new JobPersistenceException("Couldn't acquire next trigger: " + e.Message, e);
                }
            } while (true);

            // Return the acquired trigger list
            return acquiredTriggers;
        }
        public void TestStartTimeBeforeStartTimeOfDayOnInvalidDay()
        {
            DateTimeOffset startTime = dateOf(0, 0, 0, 1, 1, 2011); // Jan 1, 2011 was a saturday...
            TimeOfDay startTimeOfDay = new TimeOfDay(8, 0, 0);
            var trigger = new DailyTimeIntervalTriggerImpl();
            var daysOfWeek = new Collection.HashSet<DayOfWeek>
            {
                DayOfWeek.Monday,
                DayOfWeek.Tuesday,
                DayOfWeek.Wednesday,
                DayOfWeek.Thursday,
                DayOfWeek.Friday
            };
            trigger.DaysOfWeek = daysOfWeek;
            trigger.StartTimeUtc = startTime.ToUniversalTime();
            trigger.StartTimeOfDay = startTimeOfDay;
            trigger.RepeatIntervalUnit = IntervalUnit.Minute;
            trigger.RepeatInterval = 60;

            Assert.That(trigger.GetFireTimeAfter(dateOf(6, 0, 0, 22, 5, 2010)), Is.EqualTo(dateOf(8, 0, 0, 3, 1, 2011)));

            var fireTimes = TriggerUtils.ComputeFireTimes(trigger, null, 48);
            Assert.That(fireTimes.Count, Is.EqualTo(48));
            Assert.That(fireTimes[0], Is.EqualTo(dateOf(8, 0, 0, 3, 1, 2011)));
            Assert.That(fireTimes[47], Is.EqualTo(dateOf(23, 0, 0, 5, 1, 2011)));
        }
        public void TestMonOnly()
        {
            Collection.ISet<DayOfWeek> daysOfWeek = new Collection.HashSet<DayOfWeek>();
            daysOfWeek.Add(DayOfWeek.Monday);
            DateTimeOffset startTime = DateBuilder.DateOf(0, 0, 0, 1, 1, 2011); // SAT(7)
            TimeOfDay startTimeOfDay = new TimeOfDay(8, 0, 0);
            TimeOfDay endTimeOfDay = new TimeOfDay(17, 0, 0);
            var trigger = new DailyTimeIntervalTriggerImpl
            {
                StartTimeUtc = startTime.ToUniversalTime(),
                StartTimeOfDay = startTimeOfDay,
                EndTimeOfDay = endTimeOfDay,
                DaysOfWeek = daysOfWeek,
                RepeatIntervalUnit = IntervalUnit.Minute,
                RepeatInterval = 60
            };

            IList<DateTimeOffset> fireTimes = TriggerUtils.ComputeFireTimes(trigger, null, 48);
            Assert.AreEqual(48, fireTimes.Count);
            Assert.AreEqual(DateBuilder.DateOf(8, 0, 0, 3, 1, 2011), fireTimes[0]);
            Assert.AreEqual(DayOfWeek.Monday, fireTimes[0].DayOfWeek);
            Assert.AreEqual(DateBuilder.DateOf(8, 0, 0, 10, 1, 2011), fireTimes[10]);
            Assert.AreEqual(DayOfWeek.Monday, fireTimes[10].DayOfWeek);
            Assert.AreEqual(DateBuilder.DateOf(15, 0, 0, 31, 1, 2011), fireTimes[47]);
            Assert.AreEqual(DayOfWeek.Monday, fireTimes[47].DayOfWeek);
        }
예제 #11
0
        public void Test(IScheduler scheduler, bool clearJobs, bool scheduleJobs)
        {
            try
               {
               if (clearJobs)
               {
                   scheduler.Clear();
               }

               if (scheduleJobs)
               {
                   ICalendar cronCalendar = new CronCalendar("0/5 * * * * ?");
                   ICalendar holidayCalendar = new HolidayCalendar();

                   // QRTZNET-86
                   ITrigger t = scheduler.GetTrigger(new TriggerKey("NonExistingTrigger", "NonExistingGroup"));
                   Assert.IsNull(t);

                   AnnualCalendar cal = new AnnualCalendar();
                   scheduler.AddCalendar("annualCalendar", cal, false, true);

                   IOperableTrigger calendarsTrigger = new SimpleTriggerImpl("calendarsTrigger", "test", 20, TimeSpan.FromMilliseconds(5));
                   calendarsTrigger.CalendarName = "annualCalendar";

                   JobDetailImpl jd = new JobDetailImpl("testJob", "test", typeof(NoOpJob));
                   scheduler.ScheduleJob(jd, calendarsTrigger);

                   // QRTZNET-93
                   scheduler.AddCalendar("annualCalendar", cal, true, true);

                   scheduler.AddCalendar("baseCalendar", new BaseCalendar(), false, true);
                   scheduler.AddCalendar("cronCalendar", cronCalendar, false, true);
                   scheduler.AddCalendar("dailyCalendar", new DailyCalendar(DateTime.Now.Date, DateTime.Now.AddMinutes(1)), false, true);
                   scheduler.AddCalendar("holidayCalendar", holidayCalendar, false, true);
                   scheduler.AddCalendar("monthlyCalendar", new MonthlyCalendar(), false, true);
                   scheduler.AddCalendar("weeklyCalendar", new WeeklyCalendar(), false, true);

                   scheduler.AddCalendar("cronCalendar", cronCalendar, true, true);
                   scheduler.AddCalendar("holidayCalendar", holidayCalendar, true, true);

                   Assert.IsNotNull(scheduler.GetCalendar("annualCalendar"));

                   JobDetailImpl lonelyJob = new JobDetailImpl("lonelyJob", "lonelyGroup", typeof(SimpleRecoveryJob));
                   lonelyJob.Durable = true;
                   lonelyJob.RequestsRecovery = true;
                   scheduler.AddJob(lonelyJob, false);
                   scheduler.AddJob(lonelyJob, true);

                   string schedId = scheduler.SchedulerInstanceId;

                   int count = 1;

                   JobDetailImpl job = new JobDetailImpl("job_" + count, schedId, typeof(SimpleRecoveryJob));

                   // ask scheduler to re-Execute this job if it was in progress when
                   // the scheduler went down...
                   job.RequestsRecovery = true;
                   IOperableTrigger trigger = new SimpleTriggerImpl("trig_" + count, schedId, 20, TimeSpan.FromSeconds(5));
                   trigger.JobDataMap.Add("key", "value");
                   trigger.EndTimeUtc = DateTime.UtcNow.AddYears(10);

                   trigger.StartTimeUtc = DateTime.Now.AddMilliseconds(1000L);
                   scheduler.ScheduleJob(job, trigger);

                   // check that trigger was stored
                   ITrigger persisted = scheduler.GetTrigger(new TriggerKey("trig_" + count, schedId));
                   Assert.IsNotNull(persisted);
                   Assert.IsTrue(persisted is SimpleTriggerImpl);

                   count++;
                   job = new JobDetailImpl("job_" + count, schedId, typeof(SimpleRecoveryJob));
                   // ask scheduler to re-Execute this job if it was in progress when
                   // the scheduler went down...
                   job.RequestsRecovery = (true);
                   trigger = new SimpleTriggerImpl("trig_" + count, schedId, 20, TimeSpan.FromSeconds(5));

                   trigger.StartTimeUtc = (DateTime.Now.AddMilliseconds(2000L));
                   scheduler.ScheduleJob(job, trigger);

                   count++;
                   job = new JobDetailImpl("job_" + count, schedId, typeof(SimpleRecoveryStatefulJob));
                   // ask scheduler to re-Execute this job if it was in progress when
                   // the scheduler went down...
                   job.RequestsRecovery = (true);
                   trigger = new SimpleTriggerImpl("trig_" + count, schedId, 20, TimeSpan.FromSeconds(3));

                   trigger.StartTimeUtc = (DateTime.Now.AddMilliseconds(1000L));
                   scheduler.ScheduleJob(job, trigger);

                   count++;
                   job = new JobDetailImpl("job_" + count, schedId, typeof(SimpleRecoveryJob));
                   // ask scheduler to re-Execute this job if it was in progress when
                   // the scheduler went down...
                   job.RequestsRecovery = (true);
                   trigger = new SimpleTriggerImpl("trig_" + count, schedId, 20, TimeSpan.FromSeconds(4));

                   trigger.StartTimeUtc = (DateTime.Now.AddMilliseconds(1000L));
                   scheduler.ScheduleJob(job, trigger);

                   count++;
                   job = new JobDetailImpl("job_" + count, schedId, typeof(SimpleRecoveryJob));
                   // ask scheduler to re-Execute this job if it was in progress when
                   // the scheduler went down...
                   job.RequestsRecovery = (true);
                   trigger = new SimpleTriggerImpl("trig_" + count, schedId, 20, TimeSpan.FromMilliseconds(4500));
                   scheduler.ScheduleJob(job, trigger);

                   count++;
                   job = new JobDetailImpl("job_" + count, schedId, typeof(SimpleRecoveryJob));
                   // ask scheduler to re-Execute this job if it was in progress when
                   // the scheduler went down...
                   job.RequestsRecovery = (true);
                   IOperableTrigger ct = new CronTriggerImpl("cron_trig_" + count, schedId, "0/10 * * * * ?");
                   ct.JobDataMap.Add("key", "value");
                   ct.StartTimeUtc = DateTime.Now.AddMilliseconds(1000);

                   scheduler.ScheduleJob(job, ct);

                   count++;
                   job = new JobDetailImpl("job_" + count, schedId, typeof(SimpleRecoveryJob));
                   // ask scheduler to re-Execute this job if it was in progress when
                   // the scheduler went down...
                   job.RequestsRecovery = (true);
                   DailyTimeIntervalTriggerImpl nt = new DailyTimeIntervalTriggerImpl("nth_trig_" + count, schedId, new TimeOfDay(1, 1, 1), new TimeOfDay(23, 30, 0), IntervalUnit.Hour, 1);
                   nt.StartTimeUtc = DateTime.Now.Date.AddMilliseconds(1000);

                   scheduler.ScheduleJob(job, nt);

                   DailyTimeIntervalTriggerImpl nt2 = new DailyTimeIntervalTriggerImpl();
                   nt2.Key = new TriggerKey("nth_trig2_" + count, schedId);
                   nt2.StartTimeUtc = DateTime.Now.Date.AddMilliseconds(1000);
                   nt2.JobKey = job.Key;
                   scheduler.ScheduleJob(nt2);

                   // GitHub issue #92
                   scheduler.GetTrigger(nt2.Key);

                   // GitHub issue #98
                   nt2.StartTimeOfDay = new TimeOfDay(1, 2, 3);
                   nt2.EndTimeOfDay = new TimeOfDay(2, 3, 4);

                   scheduler.UnscheduleJob(nt2.Key);
                   scheduler.ScheduleJob(nt2);

                   var triggerFromDb = (IDailyTimeIntervalTrigger) scheduler.GetTrigger(nt2.Key);
                   Assert.That(triggerFromDb.StartTimeOfDay.Hour, Is.EqualTo(1));
                   Assert.That(triggerFromDb.StartTimeOfDay.Minute, Is.EqualTo(2));
                   Assert.That(triggerFromDb.StartTimeOfDay.Second, Is.EqualTo(3));

                   Assert.That(triggerFromDb.EndTimeOfDay.Hour, Is.EqualTo(2));
                   Assert.That(triggerFromDb.EndTimeOfDay.Minute, Is.EqualTo(3));
                   Assert.That(triggerFromDb.EndTimeOfDay.Second, Is.EqualTo(4));

                   job.RequestsRecovery = (true);
                   CalendarIntervalTriggerImpl intervalTrigger = new CalendarIntervalTriggerImpl(
                       "calint_trig_" + count,
                       schedId,
                       DateTime.UtcNow.AddMilliseconds(300),
                       DateTime.UtcNow.AddMinutes(1),
                       IntervalUnit.Second,
                       8);
                   intervalTrigger.JobKey = job.Key;

                   scheduler.ScheduleJob(intervalTrigger);

                   // bulk operations
                   var info = new Dictionary<IJobDetail, Collection.ISet<ITrigger>>();
                   IJobDetail detail = new JobDetailImpl("job_" + count, schedId, typeof(SimpleRecoveryJob));
                   ITrigger simple = new SimpleTriggerImpl("trig_" + count, schedId, 20, TimeSpan.FromMilliseconds(4500));
                   var triggers = new Collection.HashSet<ITrigger>();
                   triggers.Add(simple);
                   info[detail] = triggers;

                   scheduler.ScheduleJobs(info, true);

                   Assert.IsTrue(scheduler.CheckExists(detail.Key));
                   Assert.IsTrue(scheduler.CheckExists(simple.Key));

                   // QRTZNET-243
                   scheduler.GetJobKeys(GroupMatcher<JobKey>.GroupContains("a").DeepClone());
                   scheduler.GetJobKeys(GroupMatcher<JobKey>.GroupEndsWith("a").DeepClone());
                   scheduler.GetJobKeys(GroupMatcher<JobKey>.GroupStartsWith("a").DeepClone());
                   scheduler.GetJobKeys(GroupMatcher<JobKey>.GroupEquals("a").DeepClone());

                   scheduler.GetTriggerKeys(GroupMatcher<TriggerKey>.GroupContains("a").DeepClone());
                   scheduler.GetTriggerKeys(GroupMatcher<TriggerKey>.GroupEndsWith("a").DeepClone());
                   scheduler.GetTriggerKeys(GroupMatcher<TriggerKey>.GroupStartsWith("a").DeepClone());
                   scheduler.GetTriggerKeys(GroupMatcher<TriggerKey>.GroupEquals("a").DeepClone());

                   scheduler.Start();

                   Thread.Sleep(TimeSpan.FromSeconds(3));

                   scheduler.PauseAll();

                   scheduler.ResumeAll();

                   scheduler.PauseJob(new JobKey("job_1", schedId));

                   scheduler.ResumeJob(new JobKey("job_1", schedId));

                   scheduler.PauseJobs(GroupMatcher<JobKey>.GroupEquals(schedId));

                   Thread.Sleep(TimeSpan.FromSeconds(1));

                   scheduler.ResumeJobs(GroupMatcher<JobKey>.GroupEquals(schedId));

                   scheduler.PauseTrigger(new TriggerKey("trig_2", schedId));
                   scheduler.ResumeTrigger(new TriggerKey("trig_2", schedId));

                   scheduler.PauseTriggers(GroupMatcher<TriggerKey>.GroupEquals(schedId));

                   Assert.AreEqual(1, scheduler.GetPausedTriggerGroups().Count);

                   Thread.Sleep(TimeSpan.FromSeconds(3));
                   scheduler.ResumeTriggers(GroupMatcher<TriggerKey>.GroupEquals(schedId));

                   Assert.IsNotNull(scheduler.GetTrigger(new TriggerKey("trig_2", schedId)));
                   Assert.IsNotNull(scheduler.GetJobDetail(new JobKey("job_1", schedId)));
                   Assert.IsNotNull(scheduler.GetMetaData());
                   Assert.IsNotNull(scheduler.GetCalendar("weeklyCalendar"));

                   Thread.Sleep(TimeSpan.FromSeconds(20));

                   scheduler.Standby();

                   CollectionAssert.IsNotEmpty(scheduler.GetCalendarNames());
                   CollectionAssert.IsNotEmpty(scheduler.GetJobKeys(GroupMatcher<JobKey>.GroupEquals(schedId)));

                   CollectionAssert.IsNotEmpty(scheduler.GetTriggersOfJob(new JobKey("job_2", schedId)));
                   Assert.IsNotNull(scheduler.GetJobDetail(new JobKey("job_2", schedId)));

                   scheduler.DeleteCalendar("cronCalendar");
                   scheduler.DeleteCalendar("holidayCalendar");
                   scheduler.DeleteJob(new JobKey("lonelyJob", "lonelyGroup"));
                   scheduler.DeleteJob(job.Key);

                   scheduler.GetJobGroupNames();
                   scheduler.GetCalendarNames();
                   scheduler.GetTriggerGroupNames();
               }
               }
               finally
               {
               scheduler.Shutdown(false);
               }
        }
예제 #12
0
        public void TestScheduleMultipleTriggersForAJob()
        {
            IJobDetail job = JobBuilder.Create<TestJob>().WithIdentity("job1", "group1").Build();
            ITrigger trigger1 = TriggerBuilder.Create()
                .WithIdentity("trigger1", "group1")
                .StartNow()
                .WithSimpleSchedule(x => x.WithIntervalInSeconds(1).RepeatForever())
                .Build();
            ITrigger trigger2 = TriggerBuilder.Create()
                .WithIdentity("trigger2", "group1")
                .StartNow()
                .WithSimpleSchedule(x => x.WithIntervalInSeconds(1).RepeatForever())
                .Build();

            Collection.ISet<ITrigger> triggersForJob = new Collection.HashSet<ITrigger>();
            triggersForJob.Add(trigger1);
            triggersForJob.Add(trigger2);

            IScheduler sched = CreateScheduler("testScheduleMultipleTriggersForAJob", 5);
            sched.ScheduleJob(job, triggersForJob, true);

            IList<ITrigger> triggersOfJob = sched.GetTriggersOfJob(job.Key);
            Assert.That(triggersOfJob.Count, Is.EqualTo(2));
            Assert.That(triggersOfJob.Contains(trigger1));
            Assert.That(triggersOfJob.Contains(trigger2));

            sched.Shutdown(false);
        }
예제 #13
0
        /// <summary>
        /// Resume (un-pause) all of the <see cref="ITrigger" />s
        /// in the given group.
        /// <p>
        /// If any <see cref="ITrigger" /> missed one or more fire-times, then the
        /// <see cref="ITrigger" />'s misfire instruction will be applied.
        /// </p>
        /// </summary>
        public IList<string> ResumeTriggers(GroupMatcher<TriggerKey> matcher)
        {
            try
            {
                DeletePausedTriggerGroup(matcher);
                Collection.HashSet<string> groups = new Collection.HashSet<string>();

                Collection.ISet<TriggerKey> keys = GetTriggerKeys(matcher);

                foreach (TriggerKey key in keys)
                {
                    ResumeTrigger(key);
                    groups.Add(key.Group);
                }

                return new List<string>(groups);
            }
            catch (Exception e)
            {
                throw new JobPersistenceException("Couldn't resume trigger group '" + matcher + "': " + e.Message, e);
            }
        }
예제 #14
0
        /// <summary>
        /// Resume (un-pause) all of the <see cref="IJob" />s in
        /// the given group.
        /// <p>
        /// If any of the <see cref="IJob" /> s had <see cref="ITrigger" /> s that
        /// missed one or more fire-times, then the <see cref="ITrigger" />'s
        /// misfire instruction will be applied.
        /// </p> 
        /// </summary>
        public Collection.ISet<string> ResumeJobs(GroupMatcher<JobKey> matcher)
        {
            Collection.ISet<String> groupNames = new Collection.HashSet<string>();
            Collection.ISet<JobKey> jobKeys = GetJobKeys(matcher);

            foreach (JobKey jobKey in jobKeys)
            {
                ResumeJob(jobKey);
                groupNames.Add(jobKey.Group);
            }
            return groupNames;
        }
예제 #15
0
        /// <summary>
        /// Pause all of the <see cref="IJob" />s in the given
        /// group - by pausing all of their <see cref="ITrigger" />s.
        /// <p>
        /// The JobStore should "remember" that the group is paused, and impose the
        /// pause on any new jobs that are added to the group while the group is
        /// paused.
        /// </p>
        /// </summary>
        /// <seealso cref="string">
        /// </seealso>
        public IList<string> PauseJobs(GroupMatcher<JobKey> matcher)
        {
            Collection.ISet<string> groupNames = new Collection.HashSet<string>();
            Collection.ISet<JobKey> jobKeys = GetJobKeys(matcher);

            foreach (JobKey jobKey in jobKeys)
            {
                PauseJob(jobKey);
                groupNames.Add(jobKey.Group);
            }

            return new List<string>(groupNames);
        }