/// <summary> /// 注册事件 /// </summary> /// <param name="jobi"></param> /// <param name="groupName">监听的任务所属组</param> /// <param name="name">Scheduler名称</param> /// <returns></returns> public async Task AddJobListener(IJobListener jobi, string groupName, string name = defaultScheduler) { this.SchedulerList[name].ListenerManager.AddJobListener(jobi, GroupMatcher <JobKey> .GroupEquals(groupName)); }
/// <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); }
/// <summary> /// Pause all of the <see cref="ITrigger" />s in the given group. /// <para> /// The JobStore should "remember" that the group is paused, and impose the /// pause on any new triggers that are added to the group while the group is /// paused. /// </para> /// </summary> public virtual Collection.ISet<string> PauseTriggers(GroupMatcher<TriggerKey> matcher) { IList<string> pausedGroups; lock (lockObject) { pausedGroups = new List<string>(); StringOperator op = matcher.CompareWithOperator; if (op == StringOperator.Equality) { this.PausedTriggerGroups.Save( new BsonDocument( new BsonElement("_id", matcher.CompareToValue))); pausedGroups.Add(matcher.CompareToValue); } else { IList<string> groups = this.GetTriggerGroupNames(); foreach (string group in groups) { if (op.Evaluate(group, matcher.CompareToValue)) { this.PausedTriggerGroups.Save( new BsonDocument( new BsonElement("_id", matcher.CompareToValue))); pausedGroups.Add(matcher.CompareToValue); } } } foreach (string pausedGroup in pausedGroups) { Collection.ISet<TriggerKey> keys = this.GetTriggerKeys(GroupMatcher<TriggerKey>.GroupEquals(pausedGroup)); foreach (TriggerKey key in keys) { this.PauseTrigger(key); } } } return new Collection.HashSet<string>(pausedGroups); }
/// <summary> /// Get the names of all of the <see cref="ITrigger" /> s /// that have the given group name. /// </summary> /// <remarks> /// If there are no triggers in the given group name, the result should be a /// zero-length array (not <see langword="null" />). /// </remarks> public Collection.ISet<TriggerKey> GetTriggerKeys(GroupMatcher<TriggerKey> matcher) { // no locks necessary for read... return (Collection.ISet<TriggerKey>)ExecuteWithoutLock(conn => GetTriggerNames(conn, matcher)); }
/// <summary> /// Calls the equivalent method on the 'proxied' <see cref="QuartzScheduler" />. /// </summary> public virtual Collection.ISet<TriggerKey> GetTriggerKeys(GroupMatcher<TriggerKey> matcher) { try { return GetRemoteScheduler().GetTriggerKeys(matcher); } catch (RemotingException re) { throw InvalidateHandleCreateException("Error communicating with remote scheduler.", re); } }
/// <summary> /// Resume (un-pause) all of the <see cref="T:Quartz.IJob"/>s in /// the given group. /// <para> /// If any of the <see cref="T:Quartz.IJob"/> s had <see cref="T:Quartz.ITrigger"/> s that /// missed one or more fire-times, then the <see cref="T:Quartz.ITrigger"/>'s /// misfire instruction will be applied. /// </para> /// </summary> public override global::Quartz.Collection.ISet<string> ResumeJobs(GroupMatcher<JobKey> matcher) { var resumedJobGroups = new List<string>(); if (matcher.CompareWithOperator.Equals(StringOperator.Equality)) { var jobGroupSetKey = RedisJobStoreSchema.JobGroupSetKey(matcher.CompareToValue); var removedPausedResult = Db.SetRemove(RedisJobStoreSchema.PausedJobGroupsSetKey(), jobGroupSetKey); var jobsResult = Db.SetMembers(jobGroupSetKey); if (removedPausedResult) { resumedJobGroups.Add(RedisJobStoreSchema.JobGroup(jobGroupSetKey)); } foreach (var job in jobsResult) { ResumeJob(RedisJobStoreSchema.JobKey(job)); } } else { foreach (var jobGroupSetKey in Db.SetMembers(RedisJobStoreSchema.JobGroupsSetKey())) { if (matcher.CompareWithOperator.Evaluate(RedisJobStoreSchema.JobGroup(jobGroupSetKey), matcher.CompareToValue)) { resumedJobGroups.AddRange(ResumeJobs( GroupMatcher<JobKey>.GroupEquals(RedisJobStoreSchema.JobGroup(jobGroupSetKey)))); } } } return new global::Quartz.Collection.HashSet<string>(resumedJobGroups); }
public virtual IList<string> ResumeTriggers(GroupMatcher<TriggerKey> matcher) { return (IList<string>)ExecuteInLock(LockTriggerAccess, conn => ResumeTriggers(conn, matcher)); }
/// <summary> /// Calls the equivalent method on the 'proxied' <see cref="QuartzScheduler" />. /// </summary> public virtual void ResumeJobs(GroupMatcher <JobKey> matcher) { sched.ResumeJobs(matcher); }
/// <summary> /// Calls the equivalent method on the 'proxied' <see cref="QuartzScheduler" />. /// </summary> public virtual Collection.ISet <JobKey> GetJobKeys(GroupMatcher <JobKey> matcher) { return(sched.GetJobKeys(matcher)); }
/// <summary> /// Calls the equivalent method on the 'proxied' <see cref="QuartzScheduler" />. /// </summary> public virtual void PauseJobs(GroupMatcher <JobKey> matcher) { sched.PauseJobs(matcher); }
/// <summary> /// Calls the equivalent method on the 'proxied' <see cref="QuartzScheduler" />. /// </summary> public virtual void ResumeTriggers(GroupMatcher <TriggerKey> matcher) { sched.ResumeTriggers(matcher); }
/// <summary> /// Calls the equivalent method on the 'proxied' <see cref="QuartzScheduler" />. /// </summary> public virtual void PauseTriggers(GroupMatcher <TriggerKey> matcher) { sched.PauseTriggers(matcher); }
protected override void PerformOperation(GroupInput input) { var keys = Scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEquals(input.Group)); Scheduler.DeleteJobs(keys.ToList()); }
public List <JobInfo> List() { try { var scheduler = QuartzSchedulerMgr.GetScheduler(); var groups = scheduler.GetJobGroupNames(); var list = new List <JobInfo>(); foreach (var groupName in groups) { foreach (var jobKey in QuartzSchedulerMgr.GetScheduler().GetJobKeys(GroupMatcher <JobKey> .GroupEquals(groupName))) { string jobName = jobKey.Name; string jobGroup = jobKey.Group; DateTimeOffset?nextFire = null; var triggers = QuartzSchedulerMgr.GetScheduler().GetTriggersOfJob(jobKey); foreach (ITrigger trigger in triggers) { nextFire = trigger.GetNextFireTimeUtc(); } list.Add(new JobInfo { JobGroup = jobGroup, JobName = jobName, Triggers = triggers, NextFire = nextFire }); } } return(list); } catch (Exception ex) { throw ex; } }
protected virtual Collection.ISet<IJobDetail> GetScheduledJobDetails(ConnectionAndTransactionHolder conn, GroupMatcher<JobKey> matcher) { Collection.ISet<IJobDetail> jobs; try { jobs = Delegate.SelectScheduledJobDetailsInGroup(conn, matcher, TypeLoadHelper); } catch (Exception e) { throw new JobPersistenceException("Couldn't obtain job names: " + e.Message, e); } return jobs; }
/// <summary> /// Calls the equivalent method on the 'proxied' <see cref="QuartzScheduler" />. /// </summary> public virtual Collection.ISet <TriggerKey> GetTriggerKeys(GroupMatcher <TriggerKey> matcher) { return(sched.GetTriggerKeys(matcher)); }
/// <summary> /// Pause the <see cref="T:Quartz.IJob"/> with the given key - by /// pausing all of its current <see cref="T:Quartz.ITrigger"/>s. /// </summary> public override IList<string> PauseJobs(GroupMatcher<JobKey> matcher) { var pausedJobGroups = new List<string>(); if (matcher.CompareWithOperator.Equals(StringOperator.Equality)) { var jobGroupSetKey = RedisJobStoreSchema.JobGroupSetKey(matcher.CompareToValue); if (Db.SetAdd(RedisJobStoreSchema.PausedJobGroupsSetKey(), jobGroupSetKey)) { pausedJobGroups.Add(RedisJobStoreSchema.JobGroup(jobGroupSetKey)); foreach (RedisValue val in Db.SetMembers(jobGroupSetKey)) { PauseJob(RedisJobStoreSchema.JobKey(val)); } } } else { var jobGroupSets = Db.SetMembers(RedisJobStoreSchema.JobGroupsSetKey()); var jobGroups = jobGroupSets.Where(jobGroupSet => matcher.CompareWithOperator.Evaluate(RedisJobStoreSchema.JobGroup(jobGroupSet), matcher.CompareToValue)).ToDictionary<RedisValue, string, RedisValue[]>(jobGroupSet => jobGroupSet, jobGroupSet => Db.SetMembers(jobGroupSet.ToString())); foreach (var jobGroup in jobGroups) { if (Db.SetAdd(RedisJobStoreSchema.PausedJobGroupsSetKey(), jobGroup.Key)) { pausedJobGroups.Add(RedisJobStoreSchema.JobGroup(jobGroup.Key)); foreach (var jobHashKey in jobGroup.Value) { PauseJob(RedisJobStoreSchema.JobKey(jobHashKey)); } } } } return pausedJobGroups; }
public void TestBasicStorageFunctions() { IScheduler sched = CreateScheduler("testBasicStorageFunctions", 2); sched.Clear(); // test basic storage functions of scheduler... IJobDetail job = JobBuilder.Create <TestJob>() .WithIdentity("j1") .StoreDurably() .Build(); Assert.That(sched.CheckExists(new JobKey("j1")), Is.False, "Unexpected existence of job named 'j1'."); sched.AddJob(job, false); Assert.That(sched.CheckExists(new JobKey("j1")), "Expected existence of job named 'j1' but checkExists return false."); job = sched.GetJobDetail(new JobKey("j1")); Assert.That(job, Is.Not.Null, "Stored job not found!"); sched.DeleteJob(new JobKey("j1")); ITrigger trigger = TriggerBuilder.Create() .WithIdentity("t1") .ForJob(job) .StartNow() .WithSimpleSchedule(x => x .RepeatForever() .WithIntervalInSeconds(5)) .Build(); Assert.That(sched.CheckExists(new TriggerKey("t1")), Is.False, "Unexpected existence of trigger named '11'."); sched.ScheduleJob(job, trigger); Assert.That(sched.CheckExists(new TriggerKey("t1")), "Expected existence of trigger named 't1' but checkExists return false."); job = sched.GetJobDetail(new JobKey("j1")); Assert.That(job, Is.Not.Null, "Stored job not found!"); trigger = sched.GetTrigger(new TriggerKey("t1")); Assert.That(trigger, Is.Not.Null, "Stored trigger not found!"); job = JobBuilder.Create <TestJob>() .WithIdentity("j2", "g1") .Build(); trigger = TriggerBuilder.Create() .WithIdentity("t2", "g1") .ForJob(job) .StartNow() .WithSimpleSchedule(x => x .RepeatForever() .WithIntervalInSeconds(5)) .Build(); sched.ScheduleJob(job, trigger); job = JobBuilder.Create <TestJob>() .WithIdentity("j3", "g1") .Build(); trigger = TriggerBuilder.Create() .WithIdentity("t3", "g1") .ForJob(job) .StartNow() .WithSimpleSchedule(x => x .RepeatForever() .WithIntervalInSeconds(5)) .Build(); sched.ScheduleJob(job, trigger); IList <string> jobGroups = sched.GetJobGroupNames(); IList <string> triggerGroups = sched.GetTriggerGroupNames(); Assert.That(jobGroups.Count, Is.EqualTo(2), "Job group list size expected to be = 2 "); Assert.That(triggerGroups.Count, Is.EqualTo(2), "Trigger group list size expected to be = 2 "); Collection.ISet <JobKey> jobKeys = sched.GetJobKeys(GroupMatcher <JobKey> .GroupEquals(JobKey.DefaultGroup)); Collection.ISet <TriggerKey> triggerKeys = sched.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals(TriggerKey.DefaultGroup)); Assert.That(jobKeys.Count, Is.EqualTo(1), "Number of jobs expected in default group was 1 "); Assert.That(triggerKeys.Count, Is.EqualTo(1), "Number of triggers expected in default group was 1 "); jobKeys = sched.GetJobKeys(GroupMatcher <JobKey> .GroupEquals("g1")); triggerKeys = sched.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals("g1")); Assert.That(jobKeys.Count, Is.EqualTo(2), "Number of jobs expected in 'g1' group was 2 "); Assert.That(triggerKeys.Count, Is.EqualTo(2), "Number of triggers expected in 'g1' group was 2 "); TriggerState s = sched.GetTriggerState(new TriggerKey("t2", "g1")); Assert.That(s.Equals(TriggerState.Normal), "State of trigger t2 expected to be NORMAL "); sched.PauseTrigger(new TriggerKey("t2", "g1")); s = sched.GetTriggerState(new TriggerKey("t2", "g1")); Assert.That(s.Equals(TriggerState.Paused), "State of trigger t2 expected to be PAUSED "); sched.ResumeTrigger(new TriggerKey("t2", "g1")); s = sched.GetTriggerState(new TriggerKey("t2", "g1")); Assert.That(s.Equals(TriggerState.Normal), "State of trigger t2 expected to be NORMAL "); Collection.ISet <string> pausedGroups = sched.GetPausedTriggerGroups(); Assert.That(pausedGroups, Is.Empty, "Size of paused trigger groups list expected to be 0 "); sched.PauseTriggers(GroupMatcher <TriggerKey> .GroupEquals("g1")); // test that adding a trigger to a paused group causes the new trigger to be paused also... job = JobBuilder.Create <TestJob>() .WithIdentity("j4", "g1") .Build(); trigger = TriggerBuilder.Create() .WithIdentity("t4", "g1") .ForJob(job) .StartNow() .WithSimpleSchedule(x => x.RepeatForever().WithIntervalInSeconds(5)) .Build(); sched.ScheduleJob(job, trigger); pausedGroups = sched.GetPausedTriggerGroups(); Assert.That(pausedGroups.Count, Is.EqualTo(1), "Size of paused trigger groups list expected to be 1 "); s = sched.GetTriggerState(new TriggerKey("t2", "g1")); Assert.That(s.Equals(TriggerState.Paused), "State of trigger t2 expected to be PAUSED "); s = sched.GetTriggerState(new TriggerKey("t4", "g1")); Assert.That(s.Equals(TriggerState.Paused), "State of trigger t4 expected to be PAUSED "); sched.ResumeTriggers(GroupMatcher <TriggerKey> .GroupEquals("g1")); s = sched.GetTriggerState(new TriggerKey("t2", "g1")); Assert.That(s.Equals(TriggerState.Normal), "State of trigger t2 expected to be NORMAL "); s = sched.GetTriggerState(new TriggerKey("t4", "g1")); Assert.That(s.Equals(TriggerState.Normal), "State of trigger t4 expected to be NORMAL "); pausedGroups = sched.GetPausedTriggerGroups(); Assert.That(pausedGroups, Is.Empty, "Size of paused trigger groups list expected to be 0 "); Assert.That(sched.UnscheduleJob(new TriggerKey("foasldfksajdflk")), Is.False, "Scheduler should have returned 'false' from attempt to unschedule non-existing trigger. "); Assert.That(sched.UnscheduleJob(new TriggerKey("t3", "g1")), "Scheduler should have returned 'true' from attempt to unschedule existing trigger. "); jobKeys = sched.GetJobKeys(GroupMatcher <JobKey> .GroupEquals("g1")); triggerKeys = sched.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals("g1")); Assert.That(jobKeys.Count, Is.EqualTo(2), "Number of jobs expected in 'g1' group was 1 "); // job should have been deleted also, because it is non-durable Assert.That(triggerKeys.Count, Is.EqualTo(2), "Number of triggers expected in 'g1' group was 1 "); Assert.That(sched.UnscheduleJob(new TriggerKey("t1")), "Scheduler should have returned 'true' from attempt to unschedule existing trigger. "); jobKeys = sched.GetJobKeys(GroupMatcher <JobKey> .GroupEquals(JobKey.DefaultGroup)); triggerKeys = sched.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals(TriggerKey.DefaultGroup)); Assert.That(jobKeys.Count, Is.EqualTo(1), "Number of jobs expected in default group was 1 "); // job should have been left in place, because it is non-durable Assert.That(triggerKeys, Is.Empty, "Number of triggers expected in default group was 0 "); sched.Shutdown(); }
/// <summary> /// Get the names of all of the <see cref="T:Quartz.ITrigger"/>s /// that have the given group name. /// <para> /// If there are no triggers in the given group name, the result should be a /// zero-length array (not <see langword="null"/>). /// </para> /// </summary> public override global::Quartz.Collection.ISet<TriggerKey> TriggerKeys(GroupMatcher<TriggerKey> matcher) { var triggerKeys = new global::Quartz.Collection.HashSet<TriggerKey>(); if (matcher.CompareWithOperator.Equals(StringOperator.Equality)) { var triggerGroupSetKey = this.RedisJobStoreSchema.TriggerGroupSetKey(matcher.CompareToValue); var triggers = this.Db.SetMembers(triggerGroupSetKey); foreach (var trigger in triggers) { triggerKeys.Add(this.RedisJobStoreSchema.TriggerKey(trigger)); } } else { var triggerGroupSets = this.Db.SetMembersAsync(this.RedisJobStoreSchema.TriggerGroupsSetKey()).Result; var triggerGroupsResult = (from groupSet in triggerGroupSets where matcher.CompareWithOperator.Evaluate(this.RedisJobStoreSchema.TriggerGroup(groupSet), matcher.CompareToValue) select Db.SetMembers(groupSet.ToString())).ToList(); foreach (var triggerHashKeys in triggerGroupsResult) { if (triggerHashKeys != null) { foreach (var triggerHashKey in triggerHashKeys) { triggerKeys.Add(this.RedisJobStoreSchema.TriggerKey(triggerHashKey)); } } } } return triggerKeys; }
public Task PauseJobs(string group) { Scheduler.PauseJobs(GroupMatcher <JobKey> .GroupEquals(group)); return(Task.CompletedTask); }
protected virtual Collection.ISet<JobKey> GetJobNames(ConnectionAndTransactionHolder conn, GroupMatcher<JobKey> matcher) { Collection.ISet<JobKey> jobNames; try { jobNames = Delegate.SelectJobsInGroup(conn, matcher); } catch (Exception e) { throw new JobPersistenceException("Couldn't obtain job names: " + e.Message, e); } return jobNames; }
/// <summary> /// 查询所有任务 /// </summary> /// <returns></returns> public async Task <ApiResult <List <JobListEntity> > > GetList() { var result = new ApiResult <List <JobListEntity> >() { statusCode = (int)ApiEnum.Error }; try { List <JobKey> jboKeyList = new List <JobKey>(); List <JobListEntity> jobInfoList = new List <JobListEntity>(); //查询redis的任务 var redisTask = RedisHelper.Get <List <ScheduleEntity> >(KeyHelper.TaskSchedulerList); if (redisTask == null || redisTask.Count == 0) { result.statusCode = (int)ApiEnum.Status; result.data = jobInfoList; return(result); } var groupNames = await Scheduler.GetJobGroupNames(); if (groupNames.Count == 0) { //说明第一次打开,增加到任务调度里面 foreach (var item in redisTask) { if (item.TriggerState == TriggerState.Normal) { await Add(item); } } //阻塞下 System.Threading.Thread.Sleep(500); //阻塞后,重新获得在任务中的组信息 groupNames = await Scheduler.GetJobGroupNames(); } foreach (var groupName in groupNames.OrderBy(t => t)) { jboKeyList.AddRange(await Scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEquals(groupName))); jobInfoList.Add(new JobListEntity() { GroupName = groupName }); } //定义一个空数组,接受已存在任务里面的任务名字,提供下面,判断是否存在 var jobNameArr = new List <string>(); foreach (var jobKey in jboKeyList.OrderBy(t => t.Name)) { var jobDetail = await Scheduler.GetJobDetail(jobKey); var triggersList = await Scheduler.GetTriggersOfJob(jobKey); var triggers = triggersList.AsEnumerable().FirstOrDefault(); foreach (var jobInfo in jobInfoList) { if (jobInfo.GroupName == jobKey.Group) { //在redis里面查询任务 var cacheTask = redisTask.Where(m => m.JobName == jobKey.Name && m.JobGroup == jobKey.Group).FirstOrDefault(); if (cacheTask != null) { jobNameArr.Add(cacheTask.JobName); cacheTask.LastErrMsg = jobDetail.JobDataMap.GetString(Constant.EXCEPTION); cacheTask.PreviousFireTime = triggers.GetPreviousFireTimeUtc()?.LocalDateTime; cacheTask.NextFireTime = triggers.GetNextFireTimeUtc()?.LocalDateTime; jobInfo.jobList.Add(cacheTask); } } } } //查询Redis中,不在运行的任务项目 var noTaskList = redisTask.Where(m => !jobNameArr.Contains(m.JobName)).ToList(); //将不运行的任务,增加到List中 if (noTaskList.Any()) { //查询组 var noRunTaskGroup = noTaskList.GroupBy(m => m.JobGroup).Select(m => m.Key).ToList(); if (noRunTaskGroup != null && noRunTaskGroup.Count > 0) { foreach (var item in noRunTaskGroup) { //根据组获得任务详细信息 var jobList = new List <ScheduleEntity>(); var noRunTaskList = noTaskList.Where(m => m.JobGroup == item).ToList(); foreach (var job in noRunTaskList) { jobList.Add(job); } jobInfoList.Add(new JobListEntity() { GroupName = item, jobList = jobList }); } } } result.data = jobInfoList; result.statusCode = (int)ApiEnum.Status; } catch (Exception ex) { result.message = ex.Message; } return(result); }
/// <summary> /// Pause all of the <see cref="ITrigger" />s in the given group. /// </summary> public virtual Collection.ISet<string> PauseTriggerGroup(ConnectionAndTransactionHolder conn, GroupMatcher<TriggerKey> matcher) { try { Delegate.UpdateTriggerGroupStateFromOtherStates(conn, matcher, StatePaused, StateAcquired, StateWaiting, StateWaiting); Delegate.UpdateTriggerGroupStateFromOtherState(conn, matcher, StatePausedBlocked, StateBlocked); IList<String> groups = Delegate.SelectTriggerGroups(conn, matcher); // make sure to account for an exact group match for a group that doesn't yet exist StringOperator op = matcher.CompareWithOperator; if (op.Equals(StringOperator.Equality) && !groups.Contains(matcher.CompareToValue)) { groups.Add(matcher.CompareToValue); } foreach (string group in groups) { if (!Delegate.IsTriggerGroupPaused(conn, group)) { Delegate.InsertPausedTriggerGroup(conn, group); } } return new Collection.HashSet<string>(groups); } catch (Exception e) { throw new JobPersistenceException("Couldn't pause trigger group '" + matcher + "': " + e.Message, e); } }
public async Task TestGetJobKeysWithLike() { var sched = await CreateScheduler(null); await sched.GetJobKeys(GroupMatcher <JobKey> .GroupStartsWith("foo")); }
/// <summary> /// Calls the equivalent method on the 'proxied' <see cref="QuartzScheduler" />. /// </summary> public virtual void ResumeTriggers(GroupMatcher<TriggerKey> matcher) { try { GetRemoteScheduler().ResumeTriggers(matcher); } catch (RemotingException re) { throw InvalidateHandleCreateException("Error communicating with remote scheduler.", re); } }
public async Task TestGetJobKeysWithEquals() { var sched = await CreateScheduler(null); await sched.GetJobKeys(GroupMatcher <JobKey> .GroupEquals("bar")); }
/// <summary> /// Get the names of all of the <see cref="ITrigger" /> s /// that have the given group name. /// </summary> public virtual Collection.ISet<TriggerKey> GetTriggerKeys(GroupMatcher<TriggerKey> matcher) { lock (lockObject) { var result = this.Triggers .FindAs<Spi.IOperableTrigger>( Query.EQ("Group", matcher.CompareToValue)) .Select(t => t.Key); return new Collection.HashSet<TriggerKey>(result); } }
public async Task Test(IScheduler scheduler, bool clearJobs, bool scheduleJobs) { try { if (clearJobs) { await scheduler.Clear(); } if (scheduleJobs) { ICalendar cronCalendar = new CronCalendar("0/5 * * * * ?"); ICalendar holidayCalendar = new HolidayCalendar(); // QRTZNET-86 ITrigger t = await scheduler.GetTrigger(new TriggerKey("NonExistingTrigger", "NonExistingGroup")); Assert.IsNull(t); AnnualCalendar cal = new AnnualCalendar(); await 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)); await scheduler.ScheduleJob(jd, calendarsTrigger); // QRTZNET-93 await scheduler.AddCalendar("annualCalendar", cal, true, true); await scheduler.AddCalendar("baseCalendar", new BaseCalendar(), false, true); await scheduler.AddCalendar("cronCalendar", cronCalendar, false, true); await scheduler.AddCalendar("dailyCalendar", new DailyCalendar(DateTime.Now.Date, DateTime.Now.AddMinutes(1)), false, true); await scheduler.AddCalendar("holidayCalendar", holidayCalendar, false, true); await scheduler.AddCalendar("monthlyCalendar", new MonthlyCalendar(), false, true); await scheduler.AddCalendar("weeklyCalendar", new WeeklyCalendar(), false, true); await scheduler.AddCalendar("cronCalendar", cronCalendar, true, true); await 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; await scheduler.AddJob(lonelyJob, false); await 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); await scheduler.ScheduleJob(job, trigger); // check that trigger was stored ITrigger persisted = await 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); await 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); await 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); await 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)); await 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); await 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; var timeZone1 = TimeZoneUtil.FindTimeZoneById("Central European Standard Time"); var timeZone2 = TimeZoneUtil.FindTimeZoneById("Mountain Standard Time"); 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); nt.TimeZone = timeZone1; await scheduler.ScheduleJob(job, nt); var loadedNt = (IDailyTimeIntervalTrigger)await scheduler.GetTrigger(nt.Key); Assert.That(loadedNt.TimeZone.Id, Is.EqualTo(timeZone1.Id)); nt.TimeZone = timeZone2; await scheduler.RescheduleJob(nt.Key, nt); loadedNt = (IDailyTimeIntervalTrigger)await scheduler.GetTrigger(nt.Key); Assert.That(loadedNt.TimeZone.Id, Is.EqualTo(timeZone2.Id)); DailyTimeIntervalTriggerImpl nt2 = new DailyTimeIntervalTriggerImpl(); nt2.Key = new TriggerKey("nth_trig2_" + count, schedId); nt2.StartTimeUtc = DateTime.Now.Date.AddMilliseconds(1000); nt2.JobKey = job.Key; await scheduler.ScheduleJob(nt2); // GitHub issue #92 await scheduler.GetTrigger(nt2.Key); // GitHub issue #98 nt2.StartTimeOfDay = new TimeOfDay(1, 2, 3); nt2.EndTimeOfDay = new TimeOfDay(2, 3, 4); await scheduler.UnscheduleJob(nt2.Key); await scheduler.ScheduleJob(nt2); var triggerFromDb = (IDailyTimeIntervalTrigger)await 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; await scheduler.ScheduleJob(intervalTrigger); #if CUSTOM_TIME_ZONES // custom time zone const string CustomTimeZoneId = "Custom TimeZone"; var webTimezone = TimeZoneInfo.CreateCustomTimeZone( CustomTimeZoneId, TimeSpan.FromMinutes(22), null, null); TimeZoneUtil.CustomResolver = id => { if (id == CustomTimeZoneId) { return(webTimezone); } return(null); }; var customTimeZoneTrigger = TriggerBuilder.Create() .WithIdentity("customTimeZoneTrigger") .WithCronSchedule("0/5 * * * * ?", x => x.InTimeZone(webTimezone)) .StartNow() .ForJob(job) .Build(); await scheduler.ScheduleJob(customTimeZoneTrigger); var loadedCustomTimeZoneTrigger = (ICronTrigger)await scheduler.GetTrigger(customTimeZoneTrigger.Key); Assert.That(loadedCustomTimeZoneTrigger.TimeZone.BaseUtcOffset, Is.EqualTo(TimeSpan.FromMinutes(22))); #endif // bulk operations var info = new Dictionary <IJobDetail, IReadOnlyCollection <ITrigger> >(); IJobDetail detail = new JobDetailImpl("job_" + count, schedId, typeof(SimpleRecoveryJob)); ITrigger simple = new SimpleTriggerImpl("trig_" + count, schedId, 20, TimeSpan.FromMilliseconds(4500)); var triggers = new List <ITrigger>(); triggers.Add(simple); info[detail] = triggers; await scheduler.ScheduleJobs(info, true); Assert.IsTrue(await scheduler.CheckExists(detail.Key)); Assert.IsTrue(await scheduler.CheckExists(simple.Key)); // QRTZNET-243 await scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupContains("a").DeepClone()); await scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEndsWith("a").DeepClone()); await scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupStartsWith("a").DeepClone()); await scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEquals("a").DeepClone()); await scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupContains("a").DeepClone()); await scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEndsWith("a").DeepClone()); await scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupStartsWith("a").DeepClone()); await scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals("a").DeepClone()); await scheduler.Start(); await Task.Delay(TimeSpan.FromSeconds(3)); await scheduler.PauseAll(); await scheduler.ResumeAll(); await scheduler.PauseJob(new JobKey("job_1", schedId)); await scheduler.ResumeJob(new JobKey("job_1", schedId)); await scheduler.PauseJobs(GroupMatcher <JobKey> .GroupEquals(schedId)); await Task.Delay(TimeSpan.FromSeconds(1)); await scheduler.ResumeJobs(GroupMatcher <JobKey> .GroupEquals(schedId)); await scheduler.PauseTrigger(new TriggerKey("trig_2", schedId)); await scheduler.ResumeTrigger(new TriggerKey("trig_2", schedId)); await scheduler.PauseTriggers(GroupMatcher <TriggerKey> .GroupEquals(schedId)); var pausedTriggerGroups = await scheduler.GetPausedTriggerGroups(); Assert.AreEqual(1, pausedTriggerGroups.Count); await Task.Delay(TimeSpan.FromSeconds(3)); await 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")); var genericjobKey = new JobKey("genericJob", "genericGroup"); GenericJobType.Reset(); var genericJob = JobBuilder.Create <GenericJobType>() .WithIdentity(genericjobKey) .StoreDurably() .Build(); await scheduler.AddJob(genericJob, false); genericJob = await scheduler.GetJobDetail(genericjobKey); Assert.That(genericJob, Is.Not.Null); await scheduler.TriggerJob(genericjobKey); GenericJobType.WaitForTrigger(TimeSpan.FromSeconds(20)); Assert.That(GenericJobType.TriggeredCount, Is.EqualTo(1)); await scheduler.Standby(); CollectionAssert.IsNotEmpty(await scheduler.GetCalendarNames()); CollectionAssert.IsNotEmpty(await scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEquals(schedId))); CollectionAssert.IsNotEmpty(await scheduler.GetTriggersOfJob(new JobKey("job_2", schedId))); Assert.IsNotNull(scheduler.GetJobDetail(new JobKey("job_2", schedId))); await scheduler.DeleteCalendar("cronCalendar"); await scheduler.DeleteCalendar("holidayCalendar"); await scheduler.DeleteJob(new JobKey("lonelyJob", "lonelyGroup")); await scheduler.DeleteJob(job.Key); await scheduler.GetJobGroupNames(); await scheduler.GetCalendarNames(); await scheduler.GetTriggerGroupNames(); await TestMatchers(scheduler); } } finally { await scheduler.Shutdown(false); } }
/// <summary> /// Resume (un-pause) all of the <see cref="ITrigger" />s in the /// matching groups. /// <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 void ResumeTriggers(GroupMatcher<TriggerKey> matcher) { ValidateState(); if (matcher == null) { matcher = GroupMatcher<TriggerKey>.GroupEquals(SchedulerConstants.DefaultGroup); } ICollection<string> pausedGroups = resources.JobStore.ResumeTriggers(matcher); NotifySchedulerThread(null); foreach (string pausedGroup in pausedGroups) { NotifySchedulerListenersResumedTriggers(pausedGroup); } }
private async Task TestMatchers(IScheduler scheduler) { await scheduler.Clear(); IJobDetail job = JobBuilder.Create <NoOpJob>().WithIdentity("job1", "aaabbbccc").StoreDurably().Build(); await scheduler.AddJob(job, true); SimpleScheduleBuilder schedule = SimpleScheduleBuilder.Create(); ITrigger trigger = TriggerBuilder.Create().WithIdentity("trig1", "aaabbbccc").WithSchedule(schedule).ForJob(job).Build(); await scheduler.ScheduleJob(trigger); job = JobBuilder.Create <NoOpJob>().WithIdentity("job1", "xxxyyyzzz").StoreDurably().Build(); await scheduler.AddJob(job, true); schedule = SimpleScheduleBuilder.Create(); trigger = TriggerBuilder.Create().WithIdentity("trig1", "xxxyyyzzz").WithSchedule(schedule).ForJob(job).Build(); await scheduler.ScheduleJob(trigger); job = JobBuilder.Create <NoOpJob>().WithIdentity("job2", "xxxyyyzzz").StoreDurably().Build(); await scheduler.AddJob(job, true); schedule = SimpleScheduleBuilder.Create(); trigger = TriggerBuilder.Create().WithIdentity("trig2", "xxxyyyzzz").WithSchedule(schedule).ForJob(job).Build(); await scheduler.ScheduleJob(trigger); var jkeys = await scheduler.GetJobKeys(GroupMatcher <JobKey> .AnyGroup()); Assert.That(jkeys.Count, Is.EqualTo(3), "Wrong number of jobs found by anything matcher"); jkeys = await scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEquals("xxxyyyzzz")); Assert.That(jkeys.Count, Is.EqualTo(2), "Wrong number of jobs found by equals matcher"); jkeys = await scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEquals("aaabbbccc")); Assert.That(jkeys.Count, Is.EqualTo(1), "Wrong number of jobs found by equals matcher"); jkeys = await scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupStartsWith("aa")); Assert.That(jkeys.Count, Is.EqualTo(1), "Wrong number of jobs found by starts with matcher"); jkeys = await scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupStartsWith("xx")); Assert.That(jkeys.Count, Is.EqualTo(2), "Wrong number of jobs found by starts with matcher"); jkeys = await scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEndsWith("cc")); Assert.That(jkeys.Count, Is.EqualTo(1), "Wrong number of jobs found by ends with matcher"); jkeys = await scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEndsWith("zzz")); Assert.That(jkeys.Count, Is.EqualTo(2), "Wrong number of jobs found by ends with matcher"); jkeys = await scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupContains("bc")); Assert.That(jkeys.Count, Is.EqualTo(1), "Wrong number of jobs found by contains with matcher"); jkeys = await scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupContains("yz")); Assert.That(jkeys.Count, Is.EqualTo(2), "Wrong number of jobs found by contains with matcher"); var tkeys = await scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .AnyGroup()); Assert.That(tkeys.Count, Is.EqualTo(3), "Wrong number of triggers found by anything matcher"); tkeys = await scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals("xxxyyyzzz")); Assert.That(tkeys.Count, Is.EqualTo(2), "Wrong number of triggers found by equals matcher"); tkeys = await scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals("aaabbbccc")); Assert.That(tkeys.Count, Is.EqualTo(1), "Wrong number of triggers found by equals matcher"); tkeys = await scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupStartsWith("aa")); Assert.That(tkeys.Count, Is.EqualTo(1), "Wrong number of triggers found by starts with matcher"); tkeys = await scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupStartsWith("xx")); Assert.That(tkeys.Count, Is.EqualTo(2), "Wrong number of triggers found by starts with matcher"); tkeys = await scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEndsWith("cc")); Assert.That(tkeys.Count, Is.EqualTo(1), "Wrong number of triggers found by ends with matcher"); tkeys = await scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEndsWith("zzz")); Assert.That(tkeys.Count, Is.EqualTo(2), "Wrong number of triggers found by ends with matcher"); tkeys = await scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupContains("bc")); Assert.That(tkeys.Count, Is.EqualTo(1), "Wrong number of triggers found by contains with matcher"); tkeys = await scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupContains("yz")); Assert.That(tkeys.Count, Is.EqualTo(2), "Wrong number of triggers found by contains with matcher"); }
/// <summary> /// Resume (un-pause) all of the <see cref="T:Quartz.ITrigger"/>s in matching groups. /// </summary> /// <remarks> /// If any <see cref="T:Quartz.ITrigger"/> missed one or more fire-times, then the /// <see cref="T:Quartz.ITrigger"/>'s misfire instruction will be applied. /// </remarks> /// <seealso cref="M:Quartz.IScheduler.PauseTriggers(Quartz.Impl.Matchers.GroupMatcher{Quartz.TriggerKey})"/> public void ResumeTriggers(GroupMatcher<TriggerKey> matcher) { _scheduler.ResumeTriggers(matcher); }
public virtual async Task StartAsync(CancellationToken cancellationToken) { var props = new NameValueCollection { { "quartz.serializer.type", "binary" }, }; if (!string.IsNullOrEmpty(_globalSettings.SqlServer.JobSchedulerConnectionString)) { // Ensure each project has a unique instanceName props.Add("quartz.scheduler.instanceName", GetType().FullName); props.Add("quartz.scheduler.instanceId", "AUTO"); props.Add("quartz.jobStore.type", "Quartz.Impl.AdoJobStore.JobStoreTX"); props.Add("quartz.jobStore.driverDelegateType", "Quartz.Impl.AdoJobStore.SqlServerDelegate"); props.Add("quartz.jobStore.useProperties", "true"); props.Add("quartz.jobStore.dataSource", "default"); props.Add("quartz.jobStore.tablePrefix", "QRTZ_"); props.Add("quartz.jobStore.clustered", "true"); props.Add("quartz.dataSource.default.provider", "SqlServer"); props.Add("quartz.dataSource.default.connectionString", _globalSettings.SqlServer.JobSchedulerConnectionString); } var factory = new StdSchedulerFactory(props); _scheduler = await factory.GetScheduler(cancellationToken); _scheduler.JobFactory = new JobFactory(_serviceProvider); _scheduler.ListenerManager.AddJobListener(new JobListener(_listenerLogger), GroupMatcher <JobKey> .AnyGroup()); await _scheduler.Start(cancellationToken); if (Jobs != null) { foreach (var(job, trigger) in Jobs) { var dupeT = await _scheduler.GetTrigger(trigger.Key); if (dupeT != null) { await _scheduler.RescheduleJob(trigger.Key, trigger); } var jobDetail = JobBuilder.Create(job) .WithIdentity(job.FullName) .Build(); var dupeJ = await _scheduler.GetJobDetail(jobDetail.Key); if (dupeJ != null) { await _scheduler.DeleteJob(jobDetail.Key); } await _scheduler.ScheduleJob(jobDetail, trigger); } } // Delete old Jobs and Triggers var existingJobKeys = await _scheduler.GetJobKeys(GroupMatcher <JobKey> .AnyGroup()); var jobKeys = Jobs.Select(j => { var job = j.Item1; return(JobBuilder.Create(job) .WithIdentity(job.FullName) .Build().Key); }); foreach (var key in existingJobKeys) { if (jobKeys.Contains(key)) { continue; } _logger.LogInformation($"Deleting old job with key {key}"); await _scheduler.DeleteJob(key); } var existingTriggerKeys = await _scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .AnyGroup()); var triggerKeys = Jobs.Select(j => j.Item2.Key); foreach (var key in existingTriggerKeys) { if (triggerKeys.Contains(key)) { continue; } _logger.LogInformation($"Unscheduling old trigger with key {key}"); await _scheduler.UnscheduleJob(key); } }
public Collection.ISet<IJobDetail> GetScheduledJobDetails(GroupMatcher<JobKey> matcher) { // no locks necessary for read... return (Collection.ISet<IJobDetail>)ExecuteWithoutLock(conn => GetScheduledJobDetails(conn, matcher)); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { // make sure you configure logging and open telemetry before quartz services services.AddLogging(loggingBuilder => { loggingBuilder.ClearProviders(); loggingBuilder.AddSerilog(dispose: true); }); services.AddOpenTelemetryTracing(builder => { builder .AddQuartzInstrumentation() .AddZipkinExporter(o => { o.Endpoint = new Uri("http://localhost:9411/api/v2/spans"); o.ServiceName = "Quartz.Examples.AspNetCore"; }) .AddJaegerExporter(o => { o.ServiceName = "Quartz.Examples.AspNetCore"; // these are the defaults o.AgentHost = "localhost"; o.AgentPort = 6831; }); }); services.AddRazorPages(); // base configuration for DI services.Configure <QuartzOptions>(Configuration.GetSection("Quartz")); services.AddQuartz(q => { // handy when part of cluster or you want to otherwise identify multiple schedulers q.SchedulerId = "Scheduler-Core"; // we take this from appsettings.json, just show it's possible // q.SchedulerName = "Quartz ASP.NET Core Sample Scheduler"; // this is default configuration if you don't alter it q.UseMicrosoftDependencyInjectionJobFactory(options => { // set to true if you want to inject scoped services like Entity Framework's DbContext options.CreateScope = false; }); // these are the defaults q.UseSimpleTypeLoader(); q.UseInMemoryStore(); q.UseDefaultThreadPool(tp => { tp.MaxConcurrency = 10; }); // quickest way to create a job with single trigger is to use ScheduleJob q.ScheduleJob <ExampleJob>(trigger => trigger .WithIdentity("Combined Configuration Trigger") .StartAt(DateBuilder.EvenSecondDate(DateTimeOffset.UtcNow.AddSeconds(7))) .WithDailyTimeIntervalSchedule(x => x.WithInterval(10, IntervalUnit.Second)) .WithDescription("my awesome trigger configured for a job with single call") ); // you can also configure individual jobs and triggers with code // this allows you to associated multiple triggers with same job // (if you want to have different job data map per trigger for example) q.AddJob <ExampleJob>(j => j .StoreDurably() // we need to store durably if no trigger is associated .WithDescription("my awesome job") ); // here's a known job for triggers var jobKey = new JobKey("awesome job", "awesome group"); q.AddJob <ExampleJob>(jobKey, j => j .WithDescription("my awesome job") ); q.AddTrigger(t => t .WithIdentity("Simple Trigger") .ForJob(jobKey) .StartNow() .WithSimpleSchedule(x => x.WithInterval(TimeSpan.FromSeconds(10)).RepeatForever()) .WithDescription("my awesome simple trigger") ); q.AddTrigger(t => t .WithIdentity("Cron Trigger") .ForJob(jobKey) .StartAt(DateBuilder.EvenSecondDate(DateTimeOffset.UtcNow.AddSeconds(3))) .WithCronSchedule("0/3 * * * * ?") .WithDescription("my awesome cron trigger") ); // auto-interrupt long-running job q.UseJobAutoInterrupt(options => { // this is the default options.DefaultMaxRunTime = TimeSpan.FromMinutes(5); }); q.ScheduleJob <SlowJob>( triggerConfigurator => triggerConfigurator .WithIdentity("slowJobTrigger") .StartNow() .WithSimpleSchedule(x => x.WithIntervalInSeconds(5).RepeatForever()), jobConfigurator => jobConfigurator .WithIdentity("slowJob") .UsingJobData(JobInterruptMonitorPlugin.JobDataMapKeyAutoInterruptable, true) // allow only five seconds for this job, overriding default configuration .UsingJobData(JobInterruptMonitorPlugin.JobDataMapKeyMaxRunTime, TimeSpan.FromSeconds(5).TotalMilliseconds.ToString(CultureInfo.InvariantCulture))); const string calendarName = "myHolidayCalendar"; q.AddCalendar <HolidayCalendar>( name: calendarName, replace: true, updateTriggers: true, x => x.AddExcludedDate(new DateTime(2020, 5, 15)) ); q.AddTrigger(t => t .WithIdentity("Daily Trigger") .ForJob(jobKey) .StartAt(DateBuilder.EvenSecondDate(DateTimeOffset.UtcNow.AddSeconds(5))) .WithDailyTimeIntervalSchedule(x => x.WithInterval(10, IntervalUnit.Second)) .WithDescription("my awesome daily time interval trigger") .ModifiedByCalendar(calendarName) ); // also add XML configuration and poll it for changes q.UseXmlSchedulingConfiguration(x => { x.Files = new[] { "~/quartz_jobs.config" }; x.ScanInterval = TimeSpan.FromMinutes(1); x.FailOnFileNotFound = true; x.FailOnSchedulingError = true; }); // convert time zones using converter that can handle Windows/Linux differences q.UseTimeZoneConverter(); // add some listeners q.AddSchedulerListener <SampleSchedulerListener>(); q.AddJobListener <SampleJobListener>(GroupMatcher <JobKey> .GroupEquals(jobKey.Group)); q.AddTriggerListener <SampleTriggerListener>(); // example of persistent job store using JSON serializer as an example /* * q.UsePersistentStore(s => * { * s.UseProperties = true; * s.RetryInterval = TimeSpan.FromSeconds(15); * s.UseSqlServer(sqlServer => * { * sqlServer.ConnectionString = "some connection string"; * // this is the default * sqlServer.TablePrefix = "QRTZ_"; * }); * s.UseJsonSerializer(); * s.UseClustering(c => * { * c.CheckinMisfireThreshold = TimeSpan.FromSeconds(20); * c.CheckinInterval = TimeSpan.FromSeconds(10); * }); * }); */ }); // we can use options pattern to support hooking your own configuration with Quartz's // because we don't use service registration api, we need to manally ensure the job is present in DI services.AddTransient <ExampleJob>(); services.Configure <SampleOptions>(Configuration.GetSection("Sample")); services.AddOptions <QuartzOptions>() .Configure <IOptions <SampleOptions> >((options, dep) => { if (!string.IsNullOrWhiteSpace(dep.Value.CronSchedule)) { var jobKey = new JobKey("options-custom-job", "custom"); options.AddJob <ExampleJob>(j => j.WithIdentity(jobKey)); options.AddTrigger(trigger => trigger .WithIdentity("options-custom-trigger", "custom") .ForJob(jobKey) .WithCronSchedule(dep.Value.CronSchedule)); } }); // ASP.NET Core hosting services.AddQuartzServer(options => { // when shutting down we want jobs to complete gracefully options.WaitForJobsToComplete = true; }); services .AddHealthChecksUI() .AddInMemoryStorage(); }
/// <summary> /// Pause all of the <see cref="T:Quartz.ITrigger"/>s in the /// given group. /// </summary> /// <remarks> /// The JobStore should "remember" that the group is paused, and impose the /// pause on any new triggers that are added to the group while the group is /// paused. /// </remarks> public override IList<string> PauseTriggers(GroupMatcher<TriggerKey> matcher) { var pausedTriggerGroups = new List<string>(); if (matcher.CompareWithOperator.Equals(StringOperator.Equality)) { var triggerGroupSetKey = this.RedisJobStoreSchema.TriggerGroupSetKey(matcher.CompareToValue); var addResult = this.Db.SetAdd(this.RedisJobStoreSchema.PausedTriggerGroupsSetKey(), triggerGroupSetKey); if (addResult) { foreach (var triggerHashKey in this.Db.SetMembers(triggerGroupSetKey)) { this.PauseTrigger(this.RedisJobStoreSchema.TriggerKey(triggerHashKey)); } pausedTriggerGroups.Add(this.RedisJobStoreSchema.TriggerGroup(triggerGroupSetKey)); } } else { var allTriggerGroups = this.Db.SetMembers(this.RedisJobStoreSchema.TriggerGroupsSetKey()); var triggerGroupsResult = allTriggerGroups.Where(groupHashKey => matcher.CompareWithOperator.Evaluate(this.RedisJobStoreSchema.TriggerGroup(groupHashKey), matcher.CompareToValue)).ToDictionary<RedisValue, string, RedisValue[]>(groupHashKey => groupHashKey, groupHashKey => Db.SetMembers(groupHashKey.ToString())); foreach (var triggerGroup in triggerGroupsResult) { var addResult = this.Db.SetAdd(this.RedisJobStoreSchema.PausedTriggerGroupsSetKey(), triggerGroup.Key); if (addResult) { foreach (var triggerHashKey in triggerGroup.Value) { this.PauseTrigger(this.RedisJobStoreSchema.TriggerKey(triggerHashKey)); } pausedTriggerGroups.Add(this.RedisJobStoreSchema.TriggerGroup(triggerGroup.Key)); } } } return pausedTriggerGroups; }
/// <summary> /// Updates the scheduled jobs. /// </summary> /// <param name="context">The context.</param> private void UpdateScheduledJobs(IJobExecutionContext context) { var scheduler = context.Scheduler; int jobsDeleted = 0; int jobsScheduleUpdated = 0; var rockContext = new Rock.Data.RockContext(); ServiceJobService jobService = new ServiceJobService(rockContext); List <ServiceJob> activeJobList = jobService.GetActiveJobs().ToList(); List <Quartz.JobKey> scheduledQuartzJobs = scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupStartsWith(string.Empty)).ToList(); // delete any jobs that are no longer exist (are are not set to active) in the database var quartsJobsToDelete = scheduledQuartzJobs.Where(a => !activeJobList.Any(j => j.Guid.Equals(a.Name.AsGuid()))); foreach (JobKey jobKey in quartsJobsToDelete) { scheduler.DeleteJob(jobKey); jobsDeleted++; } // add any jobs that are not yet scheduled var newActiveJobs = activeJobList.Where(a => !scheduledQuartzJobs.Any(q => q.Name.AsGuid().Equals(a.Guid))); foreach (Rock.Model.ServiceJob job in newActiveJobs) { const string errorSchedulingStatus = "Error scheduling Job"; try { IJobDetail jobDetail = jobService.BuildQuartzJob(job); ITrigger jobTrigger = jobService.BuildQuartzTrigger(job); // Schedule the job (unless the cron expression is set to never run for an on-demand job like rebuild streaks) if (job.CronExpression != ServiceJob.NeverScheduledCronExpression) { scheduler.ScheduleJob(jobDetail, jobTrigger); jobsScheduleUpdated++; } if (job.LastStatus == errorSchedulingStatus) { job.LastStatusMessage = string.Empty; job.LastStatus = string.Empty; rockContext.SaveChanges(); } } catch (Exception ex) { ExceptionLogService.LogException(ex, null); // create a friendly error message string message = string.Format("Error scheduling the job: {0}.\n\n{2}", job.Name, job.Assembly, ex.Message); job.LastStatusMessage = message; job.LastStatus = errorSchedulingStatus; } } rockContext.SaveChanges(); // reload the jobs in case any where added/removed scheduledQuartzJobs = scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupStartsWith(string.Empty)).ToList(); // update schedule if the schedule has changed foreach (var jobKey in scheduledQuartzJobs) { var jobCronTrigger = scheduler.GetTriggersOfJob(jobKey).OfType <ICronTrigger>().FirstOrDefault(); if (jobCronTrigger != null) { var activeJob = activeJobList.FirstOrDefault(a => a.Guid.Equals(jobKey.Name.AsGuid())); if (activeJob != null) { bool rescheduleJob = false; // fix up the schedule if it has changed if (activeJob.CronExpression != jobCronTrigger.CronExpressionString) { rescheduleJob = true; } // update the job detail if it has changed var scheduledJobDetail = scheduler.GetJobDetail(jobKey); var jobDetail = jobService.BuildQuartzJob(activeJob); if (scheduledJobDetail != null && jobDetail != null) { if (scheduledJobDetail.JobType != jobDetail.JobType) { rescheduleJob = true; } if (scheduledJobDetail.JobDataMap.ToJson() != jobDetail.JobDataMap.ToJson()) { rescheduleJob = true; } } if (rescheduleJob) { const string errorReschedulingStatus = "Error re-scheduling Job"; try { ITrigger newJobTrigger = jobService.BuildQuartzTrigger(activeJob); bool deletedSuccessfully = scheduler.DeleteJob(jobKey); scheduler.ScheduleJob(jobDetail, newJobTrigger); jobsScheduleUpdated++; if (activeJob.LastStatus == errorReschedulingStatus) { activeJob.LastStatusMessage = string.Empty; activeJob.LastStatus = string.Empty; rockContext.SaveChanges(); } } catch (Exception ex) { ExceptionLogService.LogException(ex, null); // create a friendly error message string message = string.Format("Error re-scheduling the job: {0}.\n\n{2}", activeJob.Name, activeJob.Assembly, ex.Message); activeJob.LastStatusMessage = message; activeJob.LastStatus = errorReschedulingStatus; } } } } } context.Result = string.Empty; if (jobsDeleted > 0) { context.Result += string.Format("Deleted {0} job schedule(s)", jobsDeleted); } if (jobsScheduleUpdated > 0) { context.Result += (string.IsNullOrEmpty(context.Result as string) ? "" : " and ") + string.Format("Updated {0} schedule(s)", jobsScheduleUpdated); } }
/// <summary> /// Resume (un-pause) all of the <see cref="T:Quartz.ITrigger"/>s /// in the given group. /// <para> /// If any <see cref="T:Quartz.ITrigger"/> missed one or more fire-times, then the /// <see cref="T:Quartz.ITrigger"/>'s misfire instruction will be applied. /// </para> /// </summary> public override IList<string> ResumeTriggers(GroupMatcher<TriggerKey> matcher) { var resumedTriggerGroups = new List<string>(); if (matcher.CompareWithOperator.Equals(StringOperator.Equality)) { var triggerGroupSetKey = RedisJobStoreSchema.TriggerGroupSetKey(matcher.CompareToValue); Db.SetRemove(RedisJobStoreSchema.PausedTriggerGroupsSetKey(), triggerGroupSetKey); var triggerHashKeysResult = Db.SetMembers(triggerGroupSetKey); foreach (var triggerHashKey in triggerHashKeysResult) { var trigger = RetrieveTrigger(RedisJobStoreSchema.TriggerKey(triggerHashKey)); ResumeTrigger(trigger.Key); if(!resumedTriggerGroups.Contains(trigger.Key.Group)) { resumedTriggerGroups.Add(trigger.Key.Group); } } } else { foreach (var triggerGroupSetKy in Db.SetMembersAsync(RedisJobStoreSchema.TriggerGroupsSetKey()).Result) { if (matcher.CompareWithOperator.Evaluate(RedisJobStoreSchema.TriggerGroup(triggerGroupSetKy), matcher.CompareToValue)) { resumedTriggerGroups.AddRange(ResumeTriggers(GroupMatcher<TriggerKey>.GroupEquals(RedisJobStoreSchema.TriggerGroup(triggerGroupSetKy)))); } } } return resumedTriggerGroups; }
public async Task TestOverwriteFlag() { // create temp file string tempFileName = XMLSchedulingDataProcessor.QuartzXmlFileName; // Use File.Create (as opposed to File.OpenWrite) so that if the file already exists, it will be completely // replaced instead of only overwriting the first N bytes (where N is the length of SimpleJobTrigger.xml) using (TextWriter writer = new StreamWriter(File.Create(tempFileName))) { using (StreamReader reader = new StreamReader(ReadJobXmlFromEmbeddedResource("SimpleJobTrigger.xml"))) { await writer.WriteAsync(await reader.ReadToEndAsync()); await writer.FlushAsync(); } } IScheduler scheduler = null; try { var properties = new NameValueCollection(); properties["quartz.serializer.type"] = TestConstants.DefaultSerializerType; StdSchedulerFactory factory = new StdSchedulerFactory(properties); scheduler = await factory.GetScheduler(); // Let's setup a fixture job data that we know test is not going modify it. IJobDetail job = JobBuilder.Create <NoOpJob>() .WithIdentity("job1").UsingJobData("foo", "dont_chg_me").Build(); ITrigger trigger = TriggerBuilder.Create().WithIdentity("job1").WithSchedule(SimpleScheduleBuilder.RepeatHourlyForever()).Build(); await scheduler.ScheduleJob(job, trigger); XMLSchedulingDataProcessor processor = new XMLSchedulingDataProcessor(new SimpleTypeLoadHelper()); try { await processor.ProcessFileAndScheduleJobs(scheduler, false); Assert.Fail("OverWriteExisting flag didn't work. We should get Exception when overwrite is set to false."); } catch (ObjectAlreadyExistsException) { // This is expected. Do nothing. } // We should still have what we start with. var jobKeys = await scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEquals("DEFAULT")); Assert.AreEqual(1, jobKeys.Count); var triggerKeys = await scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals("DEFAULT")); Assert.AreEqual(1, triggerKeys.Count); job = await scheduler.GetJobDetail(JobKey.Create("job1")); string fooValue = job.JobDataMap.GetString("foo"); Assert.AreEqual("dont_chg_me", fooValue); } finally { if (File.Exists(tempFileName)) { File.Delete(tempFileName); } // shutdown scheduler if (scheduler != null) { await scheduler.Shutdown(); } } }
/// <summary> /// Get the names of all of the <see cref="T:Quartz.IJob"/> s that /// have the given group name. /// <para> /// If there are no jobs in the given group name, the result should be a /// zero-length array (not <see langword="null"/>). /// </para> /// </summary> /// <param name="matcher"/> /// <returns/> public override global::Quartz.Collection.ISet<JobKey> JobKeys(GroupMatcher<JobKey> matcher) { var jobKeys = new global::Quartz.Collection.HashSet<JobKey>(); if (matcher.CompareWithOperator.Equals(StringOperator.Equality)) { var jobGroupSetKey = this.RedisJobStoreSchema.JobGroupSetKey(matcher.CompareToValue); var jobHashKeys = this.Db.SetMembers(jobGroupSetKey); if (jobHashKeys != null) { foreach (var jobHashKey in jobHashKeys) { jobKeys.Add(this.RedisJobStoreSchema.JobKey(jobHashKey)); } } } else { var jobGroupSets = this.Db.SetMembers(this.RedisJobStoreSchema.JobGroupsSetKey()); var jobGroupsResult = (from groupSet in jobGroupSets where matcher.CompareWithOperator.Evaluate(this.RedisJobStoreSchema.JobGroup(groupSet), matcher.CompareToValue) select Db.SetMembers(groupSet.ToString())).ToList(); foreach (var jobHashKey in jobGroupsResult.Where(jobHashKeys => jobHashKeys != null).SelectMany(jobHashKeys => jobHashKeys)) { jobKeys.Add(this.RedisJobStoreSchema.JobKey(jobHashKey)); } } return jobKeys; }
public async Task TesDirectivesNoOverwriteWithIgnoreDups() { // create temp file string tempFileName = XMLSchedulingDataProcessor.QuartzXmlFileName; using (TextWriter writer = new StreamWriter(File.OpenWrite(tempFileName))) { using (StreamReader reader = new StreamReader(ReadJobXmlFromEmbeddedResource("directives_overwrite_no-ignoredups.xml"))) { await writer.WriteAsync(await reader.ReadToEndAsync()); await writer.FlushAsync(); } } IScheduler scheduler = null; try { NameValueCollection properties = new NameValueCollection(); properties["quartz.serializer.type"] = TestConstants.DefaultSerializerType; StdSchedulerFactory factory = new StdSchedulerFactory(properties); scheduler = await factory.GetScheduler(); // Setup existing job with same names as in xml data. IJobDetail job = JobBuilder.Create <NoOpJob>() .WithIdentity("job1") .Build(); ITrigger trigger = TriggerBuilder.Create() .WithIdentity("job1") .WithSchedule(SimpleScheduleBuilder.RepeatHourlyForever()).Build(); await scheduler.ScheduleJob(job, trigger); job = JobBuilder.Create <NoOpJob>() .WithIdentity("job2") .Build(); trigger = TriggerBuilder.Create().WithIdentity("job2").WithSchedule(SimpleScheduleBuilder.RepeatHourlyForever()).Build(); await scheduler.ScheduleJob(job, trigger); // Now load the xml data with directives: overwrite-existing-data=false, ignore-duplicates=true ITypeLoadHelper loadHelper = new SimpleTypeLoadHelper(); loadHelper.Initialize(); XMLSchedulingDataProcessor processor = new XMLSchedulingDataProcessor(loadHelper); await processor.ProcessFileAndScheduleJobs(tempFileName, scheduler); var jobKeys = await scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEquals("DEFAULT")); Assert.AreEqual(2, jobKeys.Count); var triggerKeys = await scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals("DEFAULT")); Assert.AreEqual(2, triggerKeys.Count); } finally { if (scheduler != null) { await scheduler.Shutdown(); } } }
/// <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); } }
/// <summary> /// 获取所有作业键集合 /// </summary> /// <param name="key"></param> /// <returns></returns> public static global::Quartz.Collection.ISet <JobKey> GetJobKeys(GroupMatcher <JobKey> key) { return(Scheduler.GetJobKeys(key)); }
protected virtual Collection.ISet<TriggerKey> GetTriggerNames(ConnectionAndTransactionHolder conn, GroupMatcher<TriggerKey> matcher) { Collection.ISet<TriggerKey> triggerNames; try { triggerNames = Delegate.SelectTriggersInGroup(conn, matcher); } catch (Exception e) { throw new JobPersistenceException("Couldn't obtain trigger names: " + e.Message, e); } return triggerNames; }
protected void ExecutePreProcessCommands(IScheduler scheduler) { foreach (string group in jobGroupsToDelete) { if (group.Equals("*")) { log.Info("Deleting all jobs in ALL groups."); foreach (string groupName in scheduler.GetJobGroupNames()) { if (!jobGroupsToNeverDelete.Contains(groupName)) { foreach (JobKey key in scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEquals(groupName))) { scheduler.DeleteJob(key); } } } } else { if (!jobGroupsToNeverDelete.Contains(group)) { log.InfoFormat("Deleting all jobs in group: {}", group); foreach (JobKey key in scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEquals(group))) { scheduler.DeleteJob(key); } } } } foreach (string group in triggerGroupsToDelete) { if (group.Equals("*")) { log.Info("Deleting all triggers in ALL groups."); foreach (string groupName in scheduler.GetTriggerGroupNames()) { if (!triggerGroupsToNeverDelete.Contains(groupName)) { foreach (TriggerKey key in scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals(groupName))) { scheduler.UnscheduleJob(key); } } } } else { if (!triggerGroupsToNeverDelete.Contains(group)) { log.InfoFormat("Deleting all triggers in group: {0}", group); foreach (TriggerKey key in scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals(group))) { scheduler.UnscheduleJob(key); } } } } foreach (JobKey key in jobsToDelete) { if (!jobGroupsToNeverDelete.Contains(key.Group)) { log.InfoFormat("Deleting job: {0}", key); scheduler.DeleteJob(key); } } foreach (TriggerKey key in triggersToDelete) { if (!triggerGroupsToNeverDelete.Contains(key.Group)) { log.InfoFormat("Deleting trigger: {0}", key); scheduler.UnscheduleJob(key); } } }
/// <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); }); }
static void TestQuarz() { #region 测试验证 // Common.Config.PropertiesParser.ReadFromFileResource("test.txt"); // Run(); // Set(); // Console.Read(); #endregion // Quartzlog.LogManager.Adapter=new IScheduler scheduler = StdSchedulerFactory.GetDefaultScheduler(); //调度者 WeeklyCalendar calendar = new WeeklyCalendar(); calendar.SetDayExcluded(DayOfWeek.Thursday, true); //设置每周五不能执行; HolidayCalendar daycalendar = new HolidayCalendar(); daycalendar.AddExcludedDate(DateTime.Now); //只取日 DateTime.Now.Day MonthlyCalendar monthcalendar = new MonthlyCalendar(); monthcalendar.SetDayExcluded(16, true); //只取月 DateTime.Now.Month AnnualCalendar annualCalendar = new AnnualCalendar(); annualCalendar.SetDayExcluded(DateTime.Now, true); //只取年月日 DateTime.Now.Year CronCalendar cronCalendar = new CronCalendar("* * * 17 6 ?"); //6月17 不执行 scheduler.AddCalendar("mycalendar", calendar, true, true); //设置每周五不能执行; scheduler.AddCalendar("mycalendar", daycalendar, true, true); //某一天不执行 scheduler.AddCalendar("mycalendar", monthcalendar, true, true); //某每月某一天不执行 scheduler.AddCalendar("mycalendar", annualCalendar, true, true); //每年某一月某一日不执行 scheduler.AddCalendar("mycalendar", cronCalendar, true, true); //每年某一月某一日不执行 scheduler.Start(); var job = JobBuilder.Create <lxshJob>().WithDescription("Job") .WithIdentity("lxshJob", "lxshGroup") .UsingJobData("userName", "Joblxsh") .Build(); //任务 var job1 = JobBuilder.Create <lxshJob>().WithDescription("Job") .WithIdentity("lxshJob", "lxshGroup") .UsingJobData("userName", "Joblxsh1") .Build(); //任务 var trigger = TriggerBuilder.Create().StartNow() .WithDescription("trigger") .WithSimpleSchedule(x => x.WithIntervalInSeconds(1).WithRepeatCount(10)) // .WithCalendarIntervalSchedule(x=>x.WithIntervalInYears(1)) // .WithSimpleSchedule(x => x.WithIntervalInSeconds(1).RepeatForever()) .WithDailyTimeIntervalSchedule(x => { x.OnDaysOfTheWeek(new DayOfWeek[2] { DayOfWeek.Tuesday, DayOfWeek.Friday }); //每周二或者周五执行 x.OnEveryDay() .StartingDailyAt(TimeOfDay.HourAndMinuteOfDay(8, 00)) // 八点开始 .EndingDailyAt(TimeOfDay.HourAndMinuteOfDay(18, 00)) // 十八点开始 .WithIntervalInSeconds(1); // 每1s执行一次 }) // .ModifiedByCalendar("mycalendar") .Build(); //秒分时日月 var trigger1 = TriggerBuilder.Create().WithCronSchedule("* * * * * ?").Build(); //1秒执行一次 var trigger2 = TriggerBuilder.Create().WithCronSchedule("0 * * * * ?").Build(); //1分钟执行一次 var trigger3 = TriggerBuilder.Create().WithCronSchedule("0 0/30 8-20 * * ?").Build(); //30分钟检查一次 8-20点 var trigger4 = TriggerBuilder.Create().WithCronSchedule("* * * * * ?").Build(); scheduler.ListenerManager.AddJobListener(new lxshJobLinstener(), GroupMatcher <JobKey> .AnyGroup()); scheduler.ScheduleJob(job, trigger); //开始调度任务 // scheduler.GetTriggersOfJob(new JobKey("lxshJob")).Select(x =>x.Key.ToString() ); Console.Read(); #region WithCronSchedule // -------------------------------------- // 0 0 12 * * ? 每天12点触发 // 0 15 10 ? **每天10点15分触发 // 0 15 10 * * ? 每天10点15分触发 // 0 15 10 * * ? *每天10点15分触发 // 0 15 10 * * ? 2005 2005年每天10点15分触发 // 0 * 14 * * ? 每天下午的 2点到2点59分每分触发 // 0 0 / 5 14 * * ? 每天下午的 2点到2点59分(整点开始,每隔5分触发) // 0 0 / 5 14,18 * * ? 每天下午的 2点到2点59分(整点开始,每隔5分触发) 每天下午的 18点到18点59分(整点开始,每隔5分触发) // 0 0 - 5 14 * * ? 每天下午的 2点到2点05分每分触发 // 0 10,44 14 ? 3 WED 3月分每周三下午的 2点10分和2点44分触发 // 0 15 10 ? *MON - FRI 从周一到周五每天上午的10点15分触发 // 0 15 10 15 * ? 每月15号上午10点15分触发 // 0 15 10 L * ? 每月最后一天的10点15分触发 // 0 15 10 ? *6L 每月最后一周的星期五的10点15分触发 // 0 15 10 ? *6L 2002 - 2005 从2002年到2005年每月最后一周的星期五的10点15分触发 // 0 15 10 ? *6#3 每月的第三周的星期五开始触发 // 0 0 12 1 / 5 * ? 每月的第一个中午开始每隔5天触发一次 // 0 11 11 11 11 ? 每年的11月11号 11点11分触发(光棍节) //-------------------------------------- #endregion }
/// <summary> /// Pause all of the <see cref="ITrigger" />s in the given group. /// </summary> /// <seealso cref="ResumeTriggers(Quartz.Impl.Matchers.GroupMatcher{Quartz.TriggerKey})" /> public virtual Collection.ISet<string> PauseTriggers(GroupMatcher<TriggerKey> matcher) { return (Collection.ISet<string>)ExecuteInLock(LockTriggerAccess, conn => PauseTriggerGroup(conn, matcher)); }
public async Task StartAsync(CancellationToken cancellationToken) { this.scheduler = await this.schedulerFactory.GetScheduler(); this.scheduler.JobFactory = this.jobFactory; this.scheduler.ListenerManager.AddTriggerListener(new CommonTriggerListener(), GroupMatcher<TriggerKey>.AnyGroup()); await this.scheduler.Start(); Log.Debug("QuartzHostedService.Scheduler started."); if (this.jobs == null || !this.jobs.Any()) { Log.Warning("QuartzHostedService no jobs found."); return; } foreach (var job in this.jobs) { var jobDetail = job.GetJobDetail(); if (jobDetail != null) { await this.scheduler.AddJob(jobDetail, true); Log.Debug(string.Format("Add job({0}) into the scheduler.", jobDetail.Key)); var triggers = job.GetTriggers(); if (triggers != null) { foreach (var trigger in triggers) { await this.scheduler.ScheduleJob(trigger); Log.Debug(string.Format("Schedule the job({0}) with trigger({1})", trigger.JobKey, GetTriggerDesc(trigger))); } } } } }
/// <summary> /// Calls the equivalent method on the 'proxied' <see cref="QuartzScheduler" />. /// </summary> public virtual void PauseJobs(GroupMatcher<JobKey> matcher) { try { GetRemoteScheduler().PauseJobs(matcher); } catch (RemotingException re) { throw InvalidateHandleCreateException("Error communicating with remote scheduler.", re); } }
/// <summary> /// 根据组名开启作业 /// </summary> /// <param name="groupName">组名</param> public static void ResumeJobGroup(string groupName) { Scheduler.ResumeJobs(GroupMatcher <JobKey> .GroupEquals(groupName)); }
/// <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; }
/// <summary> /// 根据触发器组名开启作业 /// </summary> /// <param name="groupName">组名</param> public static void ResumeTriggerGroup(string groupName) { Scheduler.ResumeTriggers(GroupMatcher <TriggerKey> .GroupEquals(groupName)); }
/// <summary> /// Get the names of all of the <see cref="IJob" /> s that /// match the given group matcher. /// </summary> public virtual Collection.ISet<JobKey> GetJobKeys(GroupMatcher<JobKey> matcher) { lock (lockObject) { var result = this.Jobs .FindAs<IJobDetail>( Query.EQ("Group", matcher.CompareToValue)) .Select(j => j.Key); return new Collection.HashSet<JobKey>(result); } }
/// <summary> /// 根据组名暂停作业 /// </summary> /// <param name="groupName">组名</param> public static async Task PauseJobGroup(string groupName) { await Scheduler.PauseJobs(GroupMatcher <JobKey> .GroupEquals(groupName)); }
/// <summary> /// Pause all of the <see cref="IJobDetail" />s in the /// given group - by pausing all of their <see cref="ITrigger" />s. /// <para> /// 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. /// </para> /// </summary> public virtual IList<string> PauseJobs(GroupMatcher<JobKey> matcher) { List<string> pausedGroups = new List<String>(); lock (lockObject) { StringOperator op = matcher.CompareWithOperator; if (op == StringOperator.Equality) { this.PausedJobGroups.Save( new BsonDocument( new BsonElement("_id", matcher.CompareToValue))); pausedGroups.Add(matcher.CompareToValue); } else { IList<string> groups = this.GetJobGroupNames(); foreach (string group in groups) { if (op.Evaluate(group, matcher.CompareToValue)) { this.PausedJobGroups.Save( new BsonDocument( new BsonElement("_id", matcher.CompareToValue))); pausedGroups.Add(matcher.CompareToValue); } } } foreach (string groupName in pausedGroups) { foreach (JobKey jobKey in GetJobKeys(GroupMatcher<JobKey>.GroupEquals(groupName))) { IList<IOperableTrigger> triggers = this.GetTriggersForJob(jobKey); foreach (IOperableTrigger trigger in triggers) { this.PauseTrigger(trigger.Key); } } } } return pausedGroups; }
/// <summary> /// 根据组名暂停触发器 /// </summary> /// <param name="groupName">组名</param> public static async Task PauseTriggerGroup(string groupName) { await Scheduler.PauseTriggers(GroupMatcher <TriggerKey> .GroupEquals(groupName)); }
/// <summary> /// Pause all of the <see cref="IJobDetail" />s in the /// given group - by pausing all of their <see cref="ITrigger" />s. /// </summary> public virtual void PauseJobs(GroupMatcher<JobKey> groupMatcher) { ValidateState(); if (groupMatcher == null) { groupMatcher = GroupMatcher<JobKey>.GroupEquals(SchedulerConstants.DefaultGroup); } ICollection<string> pausedGroups = resources.JobStore.PauseJobs(groupMatcher); NotifySchedulerThread(null); foreach (string pausedGroup in pausedGroups) { NotifySchedulerListenersPausedJobs(pausedGroup); } }
/// <summary> /// Resume (un-pause) all of the <see cref="T:Quartz.IJobDetail"/>s /// in matching groups. /// </summary> /// <remarks> /// If any of the <see cref="T:Quartz.IJob"/> s had <see cref="T:Quartz.ITrigger"/> s that /// missed one or more fire-times, then the <see cref="T:Quartz.ITrigger"/>'s /// misfire instruction will be applied. /// </remarks> /// <seealso cref="M:Quartz.IScheduler.PauseJobs(Quartz.Impl.Matchers.GroupMatcher{Quartz.JobKey})"/> public void ResumeJobs(GroupMatcher<JobKey> matcher) { _scheduler.ResumeJobs(matcher); }
/// <summary> /// Get the names of all the <see cref="ITrigger" />s in /// the matching groups. /// </summary> public virtual Collection.ISet<TriggerKey> GetTriggerKeys(GroupMatcher<TriggerKey> matcher) { ValidateState(); if (matcher == null) { matcher = GroupMatcher<TriggerKey>.GroupEquals(SchedulerConstants.DefaultGroup); } return resources.JobStore.GetTriggerKeys(matcher); }
public void TestGetJobKeysWithEquals() { var sched = CreateScheduler(); sched.GetJobKeys(GroupMatcher <JobKey> .GroupEquals("bar")); }