/// <summary> /// 触发新增、删除、修改、暂停、启用、立即执行事件 /// </summary> /// <param name="schedulerFactory"></param> /// <param name="action"></param> /// <param name="QuartzOptions"></param> /// <returns></returns> public static async Task <QuartzResult> TriggerAction(this ISchedulerFactory schedulerFactory, JobAction action, QuartzOption QuartzOptions) { try { List <JobKey> jobKeys = scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEquals(QuartzOptions.GroupName)).Result.ToList(); if (jobKeys == null || jobKeys.Count() == 0) { return(QuartzResult.Error($"未找到分组[{QuartzOptions.GroupName}]")); } JobKey jobKey = jobKeys?.Where(x => x.Name == QuartzOptions.TaskName && x.Group == QuartzOptions.GroupName)?.FirstOrDefault(); if (jobKey == null) { return(QuartzResult.Error($"未找到触发器[{QuartzOptions.TaskName}]")); } var triggers = await scheduler.GetTriggersOfJob(jobKey); ITrigger trigger = triggers?.Where(x => x.JobKey.Name == QuartzOptions.TaskName && x.JobKey.Group == QuartzOptions.GroupName).FirstOrDefault(); if (trigger == null) { return(QuartzResult.Error($"未找到触发器[{QuartzOptions.TaskName}]")); } object result = null; switch (action) { case JobAction.Delete: case JobAction.Modify: await scheduler.PauseTrigger(trigger.Key); await scheduler.UnscheduleJob(trigger.Key); // 移除触发器 await scheduler.DeleteJob(trigger.JobKey); result = schedulerFactory.ModifyTaskEntity(QuartzOptions, action); break; case JobAction.Pause: case JobAction.Stop: case JobAction.Start: result = schedulerFactory.ModifyTaskEntity(QuartzOptions, action); if (action == JobAction.Pause) { await scheduler.PauseTrigger(trigger.Key); } else if (action == JobAction.Start) { await scheduler.ResumeTrigger(trigger.Key); // await scheduler.RescheduleJob(trigger.Key, trigger); } else { await scheduler.Shutdown(); } break; case JobAction.StartNow: await scheduler.TriggerJob(jobKey); break; } return(QuartzResult.Ok("成功")); } catch (Exception ex) { return(QuartzResult.Error($"失败 {ex.StackTrace}")); } finally { } }
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(); } } }
public async Task TestBasicStorageFunctions() { IScheduler sched = await CreateScheduler("testBasicStorageFunctions", 2); await sched.Clear(); // test basic storage functions of scheduler... IJobDetail job = JobBuilder.Create <TestJob>() .WithIdentity("j1") .StoreDurably() .Build(); Assert.That(await sched.CheckExists(new JobKey("j1")), Is.False, "Unexpected existence of job named 'j1'."); await sched.AddJob(job, false); Assert.That(await sched.CheckExists(new JobKey("j1")), "Expected existence of job named 'j1' but checkExists return false."); job = await sched.GetJobDetail(new JobKey("j1")); Assert.That(job, Is.Not.Null, "Stored job not found!"); await sched.DeleteJob(new JobKey("j1")); ITrigger trigger = TriggerBuilder.Create() .WithIdentity("t1") .ForJob(job) .StartNow() .WithSimpleSchedule(x => x .RepeatForever() .WithIntervalInSeconds(5)) .Build(); Assert.That(await sched.CheckExists(new TriggerKey("t1")), Is.False, "Unexpected existence of trigger named '11'."); await sched.ScheduleJob(job, trigger); Assert.That(await sched.CheckExists(new TriggerKey("t1")), "Expected existence of trigger named 't1' but checkExists return false."); job = await sched.GetJobDetail(new JobKey("j1")); Assert.That(job, Is.Not.Null, "Stored job not found!"); trigger = await 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(); await 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(); await sched.ScheduleJob(job, trigger); var jobGroups = await sched.GetJobGroupNames(); var triggerGroups = await 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 "); var jobKeys = await sched.GetJobKeys(GroupMatcher <JobKey> .GroupEquals(JobKey.DefaultGroup)); var triggerKeys = await 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 = await sched.GetJobKeys(GroupMatcher <JobKey> .GroupEquals("g1")); triggerKeys = await 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 = await sched.GetTriggerState(new TriggerKey("t2", "g1")); Assert.That(s.Equals(TriggerState.Normal), "State of trigger t2 expected to be NORMAL "); await sched.PauseTrigger(new TriggerKey("t2", "g1")); s = await sched.GetTriggerState(new TriggerKey("t2", "g1")); Assert.That(s.Equals(TriggerState.Paused), "State of trigger t2 expected to be PAUSED "); await sched.ResumeTrigger(new TriggerKey("t2", "g1")); s = await sched.GetTriggerState(new TriggerKey("t2", "g1")); Assert.That(s.Equals(TriggerState.Normal), "State of trigger t2 expected to be NORMAL "); var pausedGroups = await sched.GetPausedTriggerGroups(); Assert.That(pausedGroups, Is.Empty, "Size of paused trigger groups list expected to be 0 "); await 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(); await sched.ScheduleJob(job, trigger); pausedGroups = await sched.GetPausedTriggerGroups(); Assert.That(pausedGroups.Count, Is.EqualTo(1), "Size of paused trigger groups list expected to be 1 "); s = await sched.GetTriggerState(new TriggerKey("t2", "g1")); Assert.That(s.Equals(TriggerState.Paused), "State of trigger t2 expected to be PAUSED "); s = await sched.GetTriggerState(new TriggerKey("t4", "g1")); Assert.That(s.Equals(TriggerState.Paused), "State of trigger t4 expected to be PAUSED "); await sched.ResumeTriggers(GroupMatcher <TriggerKey> .GroupEquals("g1")); s = await sched.GetTriggerState(new TriggerKey("t2", "g1")); Assert.That(s.Equals(TriggerState.Normal), "State of trigger t2 expected to be NORMAL "); s = await sched.GetTriggerState(new TriggerKey("t4", "g1")); Assert.That(s.Equals(TriggerState.Normal), "State of trigger t4 expected to be NORMAL "); pausedGroups = await sched.GetPausedTriggerGroups(); Assert.That(pausedGroups, Is.Empty, "Size of paused trigger groups list expected to be 0 "); Assert.That(await sched.UnscheduleJob(new TriggerKey("foasldfksajdflk")), Is.False, "Scheduler should have returned 'false' from attempt to unschedule non-existing trigger. "); Assert.That(await sched.UnscheduleJob(new TriggerKey("t3", "g1")), "Scheduler should have returned 'true' from attempt to unschedule existing trigger. "); jobKeys = await sched.GetJobKeys(GroupMatcher <JobKey> .GroupEquals("g1")); triggerKeys = await 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(await sched.UnscheduleJob(new TriggerKey("t1")), "Scheduler should have returned 'true' from attempt to unschedule existing trigger. "); jobKeys = await sched.GetJobKeys(GroupMatcher <JobKey> .GroupEquals(JobKey.DefaultGroup)); triggerKeys = await 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 "); await sched.Shutdown(); }
public CommandModule() : base() { #region Trigger Commands Get["/pausetrigger/{trigger}/{group}"] = _ => { var trigger = (string)_.trigger; var group = (string)_.group; try { Scheduler.PauseTrigger(new TriggerKey(trigger, group)); return(Response.AsJson(new { r = true })); } catch (System.Exception ex) { return(Response.AsJson(new { r = false, m = ex.Message })); } }; Get["/resumetrigger/{trigger}/{group}"] = _ => { var trigger = (string)_.trigger; var group = (string)_.group; try { Scheduler.ResumeTrigger(new TriggerKey(trigger, group)); return(Response.AsJson(new { r = true })); } catch (System.Exception ex) { return(Response.AsJson(new { r = false, m = ex.Message })); } }; #endregion #region Job Commands Get["/pausejob/{job}/{group}"] = _ => { var job = (string)_.job; var group = (string)_.group; try { Scheduler.PauseJob(new JobKey(job, group)); return(Response.AsJson(new { r = true })); } catch (System.Exception ex) { return(Response.AsJson(new { r = false, m = ex.Message })); } }; Get["/resumejob/{job}/{group}"] = _ => { var job = (string)_.job; var group = (string)_.group; try { Scheduler.ResumeJob(new JobKey(job, group)); return(Response.AsJson(new { r = true })); } catch (System.Exception ex) { return(Response.AsJson(new { r = false, m = ex.Message })); } }; Get["/firejob/{job}/{group}"] = _ => { var job = (string)_.job; var group = (string)_.group; try { Scheduler.TriggerJob(new JobKey(job, group)); return(Response.AsJson(new { r = true })); } catch (System.Exception ex) { return(Response.AsJson(new { r = false, m = ex.Message })); } }; #endregion #region Group Commands Get["/pausegroup/{group}"] = _ => { var group = (string)_.group; try { Scheduler.PauseJobs(GroupMatcher <JobKey> .GroupEquals(group)); return(Response.AsJson(new { r = true })); } catch (System.Exception ex) { return(Response.AsJson(new { r = false, m = ex.Message })); } }; Get["/resumegroup/{group}"] = _ => { var group = (string)_.group; try { Scheduler.ResumeJobs(GroupMatcher <JobKey> .GroupEquals(group)); return(Response.AsJson(new { r = true })); } catch (System.Exception ex) { return(Response.AsJson(new { r = false, m = ex.Message })); } }; #endregion }
public static async Task <IScheduler> Create(bool start = true) { var scheduler = await StdSchedulerFactory.GetDefaultScheduler(); { var jobData = new JobDataMap(); jobData.Put("DateFrom", DateTime.Now); jobData.Put("QuartzAssembly", File.ReadAllBytes(typeof(IScheduler).Assembly.Location)); var job = JobBuilder.Create <DummyJob>() .WithIdentity("Sales", "REPORTS") .WithDescription("Hello Job!") .UsingJobData(jobData) .StoreDurably() .Build(); var trigger = TriggerBuilder.Create() .WithIdentity("MorningSales") .StartNow() .WithCronSchedule("0 0 8 1/1 * ? *") .Build(); await scheduler.ScheduleJob(job, trigger); trigger = TriggerBuilder.Create() .WithIdentity("MonthlySales") .ForJob(job.Key) .StartNow() .WithCronSchedule("0 0 12 1 1/1 ? *") .Build(); await scheduler.ScheduleJob(trigger); await scheduler.PauseTrigger(trigger.Key); trigger = TriggerBuilder.Create() .WithIdentity("HourlySales") .ForJob(job.Key) .StartNow() .WithSimpleSchedule(x => x.WithIntervalInHours(1).RepeatForever()) .Build(); await scheduler.ScheduleJob(trigger); } { var job = JobBuilder.Create <DummyJob>().WithIdentity("Job1").StoreDurably().Build(); await scheduler.AddJob(job, false); job = JobBuilder.Create <DummyJob>().WithIdentity("Job2").StoreDurably().Build(); await scheduler.AddJob(job, false); job = JobBuilder.Create <DummyJob>().WithIdentity("Job3").StoreDurably().Build(); await scheduler.AddJob(job, false); job = JobBuilder.Create <DummyJob>().WithIdentity("Job4").StoreDurably().Build(); await scheduler.AddJob(job, false); job = JobBuilder.Create <DummyJob>().WithIdentity("Job5").StoreDurably().Build(); await scheduler.AddJob(job, false); job = JobBuilder.Create <DummyJob>().WithIdentity("Send SMS", "CRITICAL").StoreDurably().RequestRecovery().Build(); await scheduler.AddJob(job, false); var trigger = TriggerBuilder.Create() .WithIdentity("PushAds (US)") .ForJob(job.Key) .UsingJobData("Location", "US") .StartNow() .WithCronSchedule("0 0/5 * 1/1 * ? *") .Build(); await scheduler.ScheduleJob(trigger); trigger = TriggerBuilder.Create() .WithIdentity("PushAds (EU)") .ForJob(job.Key) .UsingJobData("Location", "EU") .StartNow() .WithCronSchedule("0 0/7 * 1/1 * ? *") .Build(); await scheduler.ScheduleJob(trigger); await scheduler.PauseTriggers(GroupMatcher <TriggerKey> .GroupEquals("LONGRUNNING")); job = JobBuilder.Create <DummyJob>().WithIdentity("Send Push", "CRITICAL").StoreDurably().RequestRecovery().Build(); await scheduler.AddJob(job, false); } { var job = JobBuilder.Create <DisallowConcurrentJob>() .WithIdentity("Load CSV", "IMPORT") .StoreDurably() .Build(); var trigger = TriggerBuilder.Create() .WithIdentity("CSV_small", "FREQUENTLY") .ForJob(job) .StartNow() .WithSimpleSchedule(x => x.WithIntervalInSeconds(5).RepeatForever()) .Build(); await scheduler.ScheduleJob(job, trigger); trigger = TriggerBuilder.Create() .WithIdentity("CSV_big", "LONGRUNNING") .ForJob(job) .StartNow() .WithDailyTimeIntervalSchedule(x => x.OnMondayThroughFriday()) .Build(); await scheduler.ScheduleJob(trigger); } if (start) { await scheduler.Start(); } return(scheduler); }
/// <summary> /// 获取所有Job(详情信息 - 初始化页面调用) /// </summary> /// <returns></returns> public async Task <ApiResult <List <JobInfoEntity> > > GetAllJobAsync() { var res = new ApiResult <List <JobInfoEntity> >(); try { List <JobKey> jboKeyList = new List <JobKey>(); List <JobInfoEntity> jobInfoList = new List <JobInfoEntity>(); var groupNames = await Scheduler.GetJobGroupNames(); foreach (var groupName in groupNames.OrderBy(t => t)) { jboKeyList.AddRange(await Scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEquals(groupName))); jobInfoList.Add(new JobInfoEntity() { GroupName = groupName }); } 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(); var interval = string.Empty; if (triggers is SimpleTriggerImpl) { interval = (triggers as SimpleTriggerImpl)?.RepeatInterval.ToString(); } else { interval = (triggers as CronTriggerImpl)?.CronExpressionString; } foreach (var jobInfo in jobInfoList) { if (jobInfo.GroupName == jobKey.Group) { jobInfo.JobInfoList.Add(new JobInfo() { Name = jobKey.Name, LastErrMsg = jobDetail.JobDataMap.GetString(Constant.EXCEPTION), RequestUrl = jobDetail.JobDataMap.GetString(Constant.REQUESTURL), TriggerState = await Scheduler.GetTriggerState(triggers.Key), PreviousFireTime = triggers.GetPreviousFireTimeUtc()?.LocalDateTime, NextFireTime = triggers.GetNextFireTimeUtc()?.LocalDateTime, BeginTime = triggers.StartTimeUtc.LocalDateTime, Interval = interval, EndTime = triggers.EndTimeUtc?.LocalDateTime, Description = jobDetail.Description }); continue; } } } res.data = jobInfoList; } catch (Exception ex) { res.message = ex.Message; res.statusCode = (int)ApiEnum.Error; } return(res); }
public ICollection <JobKey> GetJobKeys() { return(_scheduler.GetJobGroupNames() .SelectMany(jobGroupName => _scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEquals(jobGroupName))) .ToList()); }
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: {0}", 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); } } }
public void TestGetJobKeysWithEquals() { var sched = CreateScheduler(); sched.GetJobKeys(GroupMatcher <JobKey> .GroupEquals("bar")); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddLogging(loggingBuilder => { loggingBuilder.ClearProviders(); loggingBuilder.AddSerilog(dispose: true); }); services.AddRazorPages(); // base configuration for DI 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"; // hooks LibLog to Microsoft logging without allowing it to detect concrete implementation // if you are using NLog, SeriLog or log4net you shouldn't need this // LibLog will be removed in Quartz 4 and Microsoft Logging will become the default q.UseMicrosoftLogging(); // we could leave DI configuration intact and then jobs need to have public no-arg constructor // the MS DI is expected to produce transient job instances q.UseMicrosoftDependencyInjectionJobFactory(options => { // if we don't have the job in DI, allow fallback to configure via default constructor options.AllowDefaultConstructor = true; }); // or // q.UseMicrosoftDependencyInjectionScopedJobFactory(); // these are the defaults q.UseSimpleTypeLoader(); q.UseInMemoryStore(); q.UseDefaultThreadPool(tp => { tp.ThreadCount = 10; }); // configure jobs with code var jobKey = new JobKey("awesome job", "awesome group"); q.AddJob <ExampleJob>(j => j .StoreDurably() .WithIdentity(jobKey) .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") ); 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") ); // also add XML configuration and poll it for changes q.UseXmlSchedulingConfiguration(x => { x.Files = new[] { "~/quartz_jobs.config" }; x.ScanInterval = TimeSpan.FromSeconds(2); 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); * }); * }); */ }); // ASP.NET Core hosting services.AddQuartzServer(options => { // when shutting down we want jobs to complete gracefully options.WaitForJobsToComplete = true; }); services .AddHealthChecksUI() .AddInMemoryStorage(); }
private void TestMatchers(IScheduler scheduler) { scheduler.Clear(); IJobDetail job = JobBuilder.Create <NoOpJob>().WithIdentity("job1", "aaabbbccc").StoreDurably().Build(); scheduler.AddJob(job, true); SimpleScheduleBuilder schedule = SimpleScheduleBuilder.Create(); ITrigger trigger = TriggerBuilder.Create().WithIdentity("trig1", "aaabbbccc").WithSchedule(schedule).ForJob(job).Build(); scheduler.ScheduleJob(trigger); job = JobBuilder.Create <NoOpJob>().WithIdentity("job1", "xxxyyyzzz").StoreDurably().Build(); scheduler.AddJob(job, true); schedule = SimpleScheduleBuilder.Create(); trigger = TriggerBuilder.Create().WithIdentity("trig1", "xxxyyyzzz").WithSchedule(schedule).ForJob(job).Build(); scheduler.ScheduleJob(trigger); job = JobBuilder.Create <NoOpJob>().WithIdentity("job2", "xxxyyyzzz").StoreDurably().Build(); scheduler.AddJob(job, true); schedule = SimpleScheduleBuilder.Create(); trigger = TriggerBuilder.Create().WithIdentity("trig2", "xxxyyyzzz").WithSchedule(schedule).ForJob(job).Build(); scheduler.ScheduleJob(trigger); Collection.ISet <JobKey> jkeys = scheduler.GetJobKeys(GroupMatcher <JobKey> .AnyGroup()); Assert.That(jkeys.Count, Is.EqualTo(3), "Wrong number of jobs found by anything matcher"); jkeys = scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEquals("xxxyyyzzz")); Assert.That(jkeys.Count, Is.EqualTo(2), "Wrong number of jobs found by equals matcher"); jkeys = scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEquals("aaabbbccc")); Assert.That(jkeys.Count, Is.EqualTo(1), "Wrong number of jobs found by equals matcher"); jkeys = scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupStartsWith("aa")); Assert.That(jkeys.Count, Is.EqualTo(1), "Wrong number of jobs found by starts with matcher"); jkeys = scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupStartsWith("xx")); Assert.That(jkeys.Count, Is.EqualTo(2), "Wrong number of jobs found by starts with matcher"); jkeys = scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEndsWith("cc")); Assert.That(jkeys.Count, Is.EqualTo(1), "Wrong number of jobs found by ends with matcher"); jkeys = scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEndsWith("zzz")); Assert.That(jkeys.Count, Is.EqualTo(2), "Wrong number of jobs found by ends with matcher"); jkeys = scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupContains("bc")); Assert.That(jkeys.Count, Is.EqualTo(1), "Wrong number of jobs found by contains with matcher"); jkeys = scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupContains("yz")); Assert.That(jkeys.Count, Is.EqualTo(2), "Wrong number of jobs found by contains with matcher"); Collection.ISet <TriggerKey> tkeys = scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .AnyGroup()); Assert.That(tkeys.Count, Is.EqualTo(3), "Wrong number of triggers found by anything matcher"); tkeys = scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals("xxxyyyzzz")); Assert.That(tkeys.Count, Is.EqualTo(2), "Wrong number of triggers found by equals matcher"); tkeys = scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals("aaabbbccc")); Assert.That(tkeys.Count, Is.EqualTo(1), "Wrong number of triggers found by equals matcher"); tkeys = scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupStartsWith("aa")); Assert.That(tkeys.Count, Is.EqualTo(1), "Wrong number of triggers found by starts with matcher"); tkeys = scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupStartsWith("xx")); Assert.That(tkeys.Count, Is.EqualTo(2), "Wrong number of triggers found by starts with matcher"); tkeys = scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEndsWith("cc")); Assert.That(tkeys.Count, Is.EqualTo(1), "Wrong number of triggers found by ends with matcher"); tkeys = scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEndsWith("zzz")); Assert.That(tkeys.Count, Is.EqualTo(2), "Wrong number of triggers found by ends with matcher"); tkeys = scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupContains("bc")); Assert.That(tkeys.Count, Is.EqualTo(1), "Wrong number of triggers found by contains with matcher"); tkeys = scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupContains("yz")); Assert.That(tkeys.Count, Is.EqualTo(2), "Wrong number of triggers found by contains with matcher"); }
// Adding a JobListener that is interested in all jobs of two particular groups: public static async Task AddAJobListener3() { NameValueCollection props = new NameValueCollection { { "quartz.serializer.type", "binary" } }; StdSchedulerFactory factory = new StdSchedulerFactory(props); IScheduler scheduler = await factory.GetScheduler(); IJobListener myJobListener = new GggJobListener(); scheduler.ListenerManager.AddJobListener(myJobListener, OrMatcher <JobKey> .Or(GroupMatcher <JobKey> .GroupEquals("myJobGroup"), GroupMatcher <JobKey> .GroupEquals("yourGroup"))); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { #region Logging // make sure you configure logging and open telemetry before quartz services services.AddLogging(loggingBuilder => { loggingBuilder.ClearProviders(); loggingBuilder.AddSerilog(dispose: true); }); services.AddRazorPages(); #endregion Logging #region Quartz // 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"; #region DI Job Factory // this is default configuration if you don't alter it q.UseMicrosoftDependencyInjectionJobFactory(options => { // if we don't have the job in DI, allow fallback to configure via default constructor options.AllowDefaultConstructor = true; // set to true if you want to inject scoped services like Entity Framework's DbContext options.CreateScope = false; }); #endregion DI Job Factory #region Default Config -- For InMemory Store -- Comment if uses Persist Store -- Commented // these are the defaults //q.UseSimpleTypeLoader(); //q.UseInMemoryStore(); //q.UseDefaultThreadPool(tp => //{ // tp.MaxConcurrency = 10; //}); #endregion Default Config -- For InMemory Store -- Comment if uses Persist Store -- Commented #region Simple Trigger //// Create a job with Single Trigger //q.ScheduleJob<FirstSample>(trigger => trigger // .WithIdentity("SomeTrigger") // .StartAt(DateBuilder.EvenSecondDate(DateTimeOffset.UtcNow.AddSeconds(5))) // .WithDailyTimeIntervalSchedule(x => x.WithInterval(10, IntervalUnit.Second)) // .WithDescription("Say somethign Trigger configured for a SaySomethingJob with single call") // ); #endregion Simple Trigger #region Configure Individual Jobs And Trigger -- Commented // 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") //); #endregion Configure Individual Jobs And Trigger -- Commented #region Second Sample Job with SampleTrigger and CronTrigger var secondSampleJobKey = new JobKey("Second Sample Job", "Sample Job Group"); q.AddJob <SecondSample>(secondSampleJobKey, j => j.WithDescription("My Second Sample Job")); // Sample Trigger for Second Sample Job q.AddTrigger(trigger => trigger .WithIdentity("SecondSample Sample Trigger") .ForJob(secondSampleJobKey) .StartNow() .WithSimpleSchedule(x => x.WithInterval(TimeSpan.FromSeconds(7)).RepeatForever()) .WithDescription("My Second Sample Trigger") ); // Cron Trigger for Second Sample Job q.AddTrigger(trigger => trigger .WithIdentity("My Second Sample Cron Trigger") .ForJob(secondSampleJobKey) .StartAt(DateBuilder.EvenSecondDate(DateTimeOffset.UtcNow.AddSeconds(3))) .WithCronSchedule("0/17 * * * * ?") .WithDescription("My Second Cron Trigger") ); #endregion Second Sample Job with SampleTrigger and CronTrigger #region TimeConverter q.UseTimeZoneConverter(); #endregion TimeConverter #region Sample Listener // Add Second Sample Listener q.AddJobListener <SecondSampleJobListener>(GroupMatcher <JobKey> .GroupEquals(secondSampleJobKey.Group)); q.AddTriggerListener <SecondSampleTriggerListener>(); q.AddSchedulerListener <SecondSampleSchedulerListener>(); #endregion Sample Listener #region Job Using Data var dataJobKey = new JobKey("AuthorInfo", "Using Data Group"); q.AddJob <UsingDataJob>(options => options.WithIdentity(dataJobKey) .UsingJobData("Name", "Nguyen Minh Van") .UsingJobData("Age", "24") .UsingJobData("Address", "District 12, Ho Chi Minh City") ); q.AddTrigger(options => options.ForJob(dataJobKey) .WithIdentity("DataJob-Trigger") .WithCronSchedule("0/5 * * * * ?")); #endregion Job Using Data #region Calender //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) //); // convert time zones using converter that can handle Windows/Linux differences //q.UseTimeZoneConverter(); #endregion Calender }); #endregion Quartz #region Quartz Options // 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)); // } // }); #endregion Quartz Options #region Quartz Server // ASP.NET Core hosting services.AddQuartzServer(options => { // when shutting down we want jobs to complete gracefully options.WaitForJobsToComplete = true; }); #endregion Quartz Server #region Other Services services .AddHealthChecksUI() .AddInMemoryStorage(); #endregion Other Services }
public Task <IReadOnlyCollection <JobKey> > GetJobKeysAsync(string groupName) { return(scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEquals(groupName))); }
/// <summary> /// /获取任务列表 /// </summary> /// <returns></returns> public PagedResultDto <JobDetailOutputDto> GetJobList(int pageIndex, string groupNames = "") { if (_scheduler == null) { return(null); } var jobList = _jobDetailRepository.Query().AsNoTracking() .Where(x => !x.IsDeleted).ToList(); if (!string.IsNullOrEmpty(groupNames)) { jobList = jobList.Where(x => x.JobGroupName == groupNames).ToList(); } var totalCount = jobList.Count; var result = new List <JobDetailOutputDto>(); foreach (var groupName in _scheduler.GetJobGroupNames().Result) { foreach (JobKey jobKey in _scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEquals(groupName)).Result) { var triggers = _scheduler.GetTriggersOfJob(jobKey).Result.ToList(); foreach (var item in triggers) { var jobViewModel = new JobDetailOutputDto { JobName = jobKey.Name, JobGroupName = jobKey.Group, TriggerGroupName = item.Key.Group, TriggerName = item.Key.Name, CurrentStatus = GetJobStatusByKey(item.Key), NextRunTime = item.GetNextFireTimeUtc() == null ? "下次不会触发运行时间" : item.GetNextFireTimeUtc()?.LocalDateTime.ToString("yyyy-MM-dd HH:mm:ss.fff"), LastRunTime = item.GetPreviousFireTimeUtc() == null ? "还未运行过" : item.GetPreviousFireTimeUtc()?.LocalDateTime.ToString("yyyy-MM-dd HH:mm:ss.fff") }; var jobInfo = jobList.FirstOrDefault(x => x.JobName == jobKey.Name && x.JobGroupName == jobKey.Group); if (jobInfo == null) { continue; }// jobViewModel.Cron = jobInfo.Cron; jobViewModel.RequestUrl = jobInfo.RequestUrl; jobViewModel.ExceptionEmail = jobInfo.ExceptionEmail; jobViewModel.Id = jobInfo.Id; jobViewModel.IsInSchedule = true; result.Add(jobViewModel); } } } foreach (var item in result) { var jobInfo = jobList.FirstOrDefault(x => x.JobName == item.JobName && x.JobGroupName == item.JobGroupName); if (jobInfo != null) { jobList.Remove(jobInfo); } } if (jobList.Count > 0) { foreach (var item in jobList) { var jobViewModel = new JobDetailOutputDto();; jobViewModel.JobName = item.JobName; jobViewModel.JobGroupName = item.JobGroupName; jobViewModel.TriggerGroupName = item.TriggerGroupName; jobViewModel.TriggerName = item.TriggerGroupName; jobViewModel.CurrentStatus = "还未加入计划中"; jobViewModel.NextRunTime = "无"; jobViewModel.LastRunTime = "无"; jobViewModel.Cron = item.Cron; jobViewModel.Id = item.Id; jobViewModel.IsInSchedule = false; jobViewModel.RequestUrl = item.RequestUrl; jobViewModel.ExceptionEmail = item.ExceptionEmail; result.Add(jobViewModel); } } result = result.Skip(10 * (pageIndex - 1)).Take(pageIndex * 10).ToList();//分页默认每页大小为10 return(new PagedResultDto <JobDetailOutputDto>(totalCount, result)); //return result; }
public async Task TestBasicStorageFunctions() { var sched = await CreateScheduler("TestBasicStorageFunctions", 2); await sched.Start(CancellationToken.None); await sched.Standby(CancellationToken.None); // test basic storage functions of scheduler... var job = JobBuilder.Create() .OfType <TestJob>() .WithIdentity("j1") .StoreDurably() .Build(); Assert.IsFalse(await sched.CheckExists(new JobKey("j1")), "Unexpected existence of job named 'j1'."); await sched.AddJob(job, false); Assert.IsTrue(await sched.CheckExists(new JobKey("j1")), "Expected existence of job named 'j1' but checkExists return false."); job = await sched.GetJobDetail(new JobKey("j1")); Assert.IsNotNull(job, "Stored job not found!"); await sched.DeleteJob(new JobKey("j1")); var trigger = TriggerBuilder.Create() .WithIdentity("t1") .ForJob(job) .StartNow() .WithSimpleSchedule(x => x.RepeatForever().WithIntervalInSeconds(5)) .Build(); Assert.IsFalse(await sched.CheckExists(new TriggerKey("t1")), "Unexpected existence of trigger named '11'."); await sched.ScheduleJob(job, trigger); Assert.IsTrue(await sched.CheckExists(new TriggerKey("t1")), "Expected existence of trigger named 't1' but checkExists return false."); job = await sched.GetJobDetail(new JobKey("j1")); Assert.IsNotNull(job, "Stored job not found!"); trigger = await sched.GetTrigger(new TriggerKey("t1")); Assert.IsNotNull(trigger, "Stored trigger not found!"); job = JobBuilder.Create() .OfType <TestJob>() .WithIdentity("j2", "g1") .Build(); trigger = TriggerBuilder.Create() .WithIdentity("t2", "g1") .ForJob(job) .StartNow() .WithSimpleSchedule(x => x.RepeatForever().WithIntervalInSeconds(5)) .Build(); await sched.ScheduleJob(job, trigger); job = JobBuilder.Create() .OfType <TestJob>() .WithIdentity("j3", "g1") .Build(); trigger = TriggerBuilder.Create() .WithIdentity("t3", "g1") .ForJob(job) .StartNow() .WithSimpleSchedule(x => x.RepeatForever().WithIntervalInSeconds(5)) .Build(); await sched.ScheduleJob(job, trigger); IList <string> jobGroups = (await sched.GetJobGroupNames()).ToList(); IList <string> triggerGroups = (await sched.GetTriggerGroupNames()).ToList(); Assert.AreEqual(3, jobGroups.Count, "Job group list size expected to be = 2 + 1 for DEFAULT"); Assert.AreEqual(2, triggerGroups.Count, "Trigger group list size expected to be = 2"); ISet <JobKey> jobKeys = (await sched.GetJobKeys(GroupMatcher <JobKey> .GroupEquals(JobKey.DefaultGroup))) .ToHashSet(); ISet <TriggerKey> triggerKeys = (await sched.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals(TriggerKey.DefaultGroup))).ToHashSet(); Assert.AreEqual(1, jobKeys.Count, "Number of jobs expected in default group was 1 "); Assert.AreEqual(1, triggerKeys.Count, "Number of triggers expected in default group was 1 "); jobKeys = (await sched.GetJobKeys(GroupMatcher <JobKey> .GroupEquals("g1"))).ToHashSet(); triggerKeys = (await sched.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals("g1"))).ToHashSet(); Assert.AreEqual(2, jobKeys.Count, "Number of jobs expected in 'g1' group was 2 "); Assert.AreEqual(2, triggerKeys.Count, "Number of triggers expected in 'g1' group was 2 "); var s = await sched.GetTriggerState(new TriggerKey("t2", "g1")); Assert.AreEqual(TriggerState.Normal, s, "State of trigger t2 expected to be NORMAL "); await sched.PauseTrigger(new TriggerKey("t2", "g1")); s = await sched.GetTriggerState(new TriggerKey("t2", "g1")); Assert.AreEqual(TriggerState.Paused, s, "State of trigger t2 expected to be PAUSED "); await sched.ResumeTrigger(new TriggerKey("t2", "g1")); s = await sched.GetTriggerState(new TriggerKey("t2", "g1")); Assert.AreEqual(TriggerState.Normal, s, "State of trigger t2 expected to be NORMAL "); ISet <string> pausedGroups = (await sched.GetPausedTriggerGroups()).ToHashSet(); Assert.AreEqual(0, pausedGroups.Count, "Size of paused trigger groups list expected to be 0 "); await 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() .OfType <TestJob>() .WithIdentity("j4", "g1") .Build(); trigger = TriggerBuilder.Create() .WithIdentity("t4", "g1") .ForJob(job) .StartNow() .WithSimpleSchedule(x => x.RepeatForever().WithIntervalInSeconds(5)) .Build(); await sched.ScheduleJob(job, trigger); pausedGroups = (await sched.GetPausedTriggerGroups()).ToHashSet(); Assert.AreEqual(1, pausedGroups.Count, "Size of paused trigger groups list expected to be 1 "); s = await sched.GetTriggerState(new TriggerKey("t2", "g1")); Assert.AreEqual(TriggerState.Paused, s, "State of trigger t2 expected to be PAUSED "); s = await sched.GetTriggerState(new TriggerKey("t4", "g1")); Assert.AreEqual(TriggerState.Paused, s, "State of trigger t4 expected to be PAUSED"); await sched.ResumeTriggers(GroupMatcher <TriggerKey> .GroupEquals("g1")); s = await sched.GetTriggerState(new TriggerKey("t2", "g1")); Assert.AreEqual(TriggerState.Normal, s, "State of trigger t2 expected to be NORMAL "); s = await sched.GetTriggerState(new TriggerKey("t4", "g1")); Assert.AreEqual(TriggerState.Normal, s, "State of trigger t2 expected to be NORMAL "); pausedGroups = (await sched.GetPausedTriggerGroups()).ToHashSet(); Assert.AreEqual(0, pausedGroups.Count, "Size of paused trigger groups list expected to be 0 "); Assert.IsFalse(await sched.UnscheduleJob(new TriggerKey("foasldfksajdflk")), "Scheduler should have returned 'false' from attempt to unschedule non-existing trigger. "); Assert.IsTrue(await sched.UnscheduleJob(new TriggerKey("t3", "g1")), "Scheduler should have returned 'true' from attempt to unschedule existing trigger. "); jobKeys = (await sched.GetJobKeys(GroupMatcher <JobKey> .GroupEquals("g1"))).ToHashSet(); triggerKeys = (await sched.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals("g1"))).ToHashSet(); Assert.AreEqual(2, jobKeys.Count, "Number of jobs expected in 'g1' group was 2 "); // job should have been deleted also, because it is non-durable Assert.AreEqual(2, triggerKeys.Count, "Number of triggers expected in 'g1' group was 2 "); Assert.IsTrue(await sched.UnscheduleJob(new TriggerKey("t1")), "Scheduler should have returned 'true' from attempt to unschedule existing trigger. "); jobKeys = (await sched.GetJobKeys(GroupMatcher <JobKey> .GroupEquals(JobKey.DefaultGroup))).ToHashSet(); triggerKeys = (await sched.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals(TriggerKey.DefaultGroup))) .ToHashSet(); Assert.AreEqual(1, jobKeys.Count, "Number of jobs expected in default group was 1 "); // job should have been left in place, because it is non-durable Assert.AreEqual(0, triggerKeys.Count, "Number of triggers expected in default group was 0 "); await sched.Shutdown(); }
public async Task <List <List <JobModel> > > Get() { List <JobModel> jobs = new List <JobModel>(); var groups = await QuartzHostedService.Scheduler.GetJobGroupNames(); foreach (var groupName in groups) { foreach (var jobKey in await QuartzHostedService.Scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEquals(groupName))) { JobModel jobModel = new JobModel { JobName = jobKey.Name, JobGroup = groupName }; jobModel.JobUrl = _jobSchedules.First(x => x.JobName == jobKey.Name)?.JobUrl; // string jobName = jobKey.Name; // string jobGroup = jobKey.Group; List <TriggerModel> triggerModels = new List <TriggerModel>(); var triggers = await QuartzHostedService.Scheduler.GetTriggersOfJob(jobKey); foreach (ITrigger trigger in triggers) { var state = await QuartzHostedService.Scheduler.GetTriggerState(trigger.Key); TriggerModel triggerModel = new TriggerModel { Name = trigger.Key.Name, Cron = trigger.Description, State = Enum.GetName(state.GetType(), state), NextExecTime = trigger.GetNextFireTimeUtc().Value.ToLocalTime().ToString("yyyy/MM/dd HH:mm:ss"), Result = _jobTriggerInfo.triggersInfo.FirstOrDefault(x => x.Name == trigger.Key.Name)?.Result }; triggerModels.Add(triggerModel); // string name = trigger.Key.Name; // string cron = trigger.Description; // string next_time = trigger.GetNextFireTimeUtc().Value.ToLocalTime().ToString("yyyy/MM/dd HH:mm:ss"); } jobModel.Triggers = triggerModels; jobs.Add(jobModel); } } var d = jobs.GroupBy(x => x.JobGroup).Select(x => x.ToList()).ToList(); return(await Task.FromResult(d)); //return _jobSchedules; }
/// <summary> /// 获取所有Job(详情信息 - 初始化页面调用) /// </summary> /// <returns></returns> public async Task <IResponseOutput> GetAllJobAsync() { List <JobKey> jboKeyList = new List <JobKey>(); List <JobInfoEntity> jobInfoEntityList = new List <JobInfoEntity>(); var groupNames = await scheduler.GetJobGroupNames(); foreach (var groupName in groupNames.OrderBy(t => t)) { jboKeyList.AddRange(await scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEquals(groupName))); jobInfoEntityList.Add(new JobInfoEntity() { GroupName = groupName }); } List <JobInfo> jobInfoList = new List <JobInfo>(); 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(); var interval = string.Empty; if (triggers is SimpleTriggerImpl) { interval = (triggers as SimpleTriggerImpl)?.RepeatInterval.ToString(); } else { interval = (triggers as CronTriggerImpl)?.CronExpressionString; } // foreach (var jobInfo in jobInfoEntityList) // { // if (jobInfo.GroupName == jobKey.Group) //{ //旧代码没有保存JobTypeEnum,所以None可以默认为Url。 var jobType = (JobTypeEnum)jobDetail.JobDataMap.GetLong(JobConstant.JobTypeEnum); jobType = jobType == JobTypeEnum.None ? JobTypeEnum.Url : jobType; var triggerAddress = string.Empty; if (jobType == JobTypeEnum.Url) { triggerAddress = jobDetail.JobDataMap.GetString(JobConstant.REQUESTURL); } else if (jobType == JobTypeEnum.Emial) { triggerAddress = jobDetail.JobDataMap.GetString(JobConstant.MailTo); } else if (jobType == JobTypeEnum.Mqtt) { triggerAddress = jobDetail.JobDataMap.GetString(JobConstant.Topic); } else if (jobType == JobTypeEnum.RabbitMQ) { triggerAddress = jobDetail.JobDataMap.GetString(JobConstant.RabbitQueue); } //Constant.MailTo jobInfoList.Add(new JobInfo() { Name = jobKey.Name, GroupName = jobKey.Group, LastErrMsg = jobDetail.JobDataMap.GetString(JobConstant.EXCEPTION), TriggerAddress = triggerAddress, TriggerState = await scheduler.GetTriggerState(triggers.Key), PreviousFireTime = triggers.GetPreviousFireTimeUtc()?.LocalDateTime, NextFireTime = triggers.GetNextFireTimeUtc()?.LocalDateTime, BeginTime = triggers.StartTimeUtc.LocalDateTime, Interval = interval, EndTime = triggers.EndTimeUtc?.LocalDateTime, Description = jobDetail.Description, RequestType = jobDetail.JobDataMap.GetString(JobConstant.REQUESTTYPE), RunNumber = jobDetail.JobDataMap.GetLong(JobConstant.RUNNUMBER), JobType = (long)jobType //(triggers as SimpleTriggerImpl)?.TimesTriggered //CronTriggerImpl 中没有 TimesTriggered 所以自己RUNNUMBER记录 }); continue; // } //} } return(ResponseOutput.Ok(jobInfoList)); }
public async Task TestBasicStorageFunctions() { NameValueCollection config = new NameValueCollection(); config["quartz.scheduler.instanceName"] = "SchedulerTest_Scheduler"; config["quartz.scheduler.instanceId"] = "AUTO"; config["quartz.threadPool.threadCount"] = "2"; config["quartz.threadPool.type"] = "Quartz.Simpl.SimpleThreadPool, Quartz"; config["quartz.serializer.type"] = TestConstants.DefaultSerializerType; IScheduler sched = await new StdSchedulerFactory(config).GetScheduler(); // test basic storage functions of scheduler... IJobDetail job = JobBuilder.Create() .OfType <TestJob>() .WithIdentity("j1") .StoreDurably() .Build(); var exists = await sched.CheckExists(new JobKey("j1")); Assert.IsFalse(exists, "Unexpected existence of job named 'j1'."); await sched.AddJob(job, false); exists = await sched.CheckExists(new JobKey("j1")); Assert.IsTrue(exists, "Expected existence of job named 'j1' but checkExists return false."); job = await sched.GetJobDetail(new JobKey("j1")); Assert.IsNotNull(job, "Stored job not found!"); await sched.DeleteJob(new JobKey("j1")); ITrigger trigger = TriggerBuilder.Create() .WithIdentity("t1") .ForJob(job) .StartNow() .WithSimpleSchedule(x => x.RepeatForever().WithIntervalInSeconds(5)) .Build(); exists = await sched.CheckExists(new TriggerKey("t1")); Assert.IsFalse(exists, "Unexpected existence of trigger named '11'."); await sched.ScheduleJob(job, trigger); exists = await sched.CheckExists(new TriggerKey("t1")); Assert.IsTrue(exists, "Expected existence of trigger named 't1' but checkExists return false."); job = await sched.GetJobDetail(new JobKey("j1")); Assert.IsNotNull(job, "Stored job not found!"); trigger = await sched.GetTrigger(new TriggerKey("t1")); Assert.IsNotNull(trigger, "Stored trigger not found!"); job = JobBuilder.Create() .OfType <TestJob>() .WithIdentity("j2", "g1") .Build(); trigger = TriggerBuilder.Create() .WithIdentity("t2", "g1") .ForJob(job) .StartNow() .WithSimpleSchedule(x => x.RepeatForever().WithIntervalInSeconds(5)) .Build(); await sched.ScheduleJob(job, trigger); job = JobBuilder.Create() .OfType <TestJob>() .WithIdentity("j3", "g1") .Build(); trigger = TriggerBuilder.Create() .WithIdentity("t3", "g1") .ForJob(job) .StartNow() .WithSimpleSchedule(x => x.RepeatForever().WithIntervalInSeconds(5)) .Build(); await sched.ScheduleJob(job, trigger); var jobGroups = await sched.GetJobGroupNames(); var triggerGroups = await sched.GetTriggerGroupNames(); Assert.AreEqual(2, jobGroups.Count, "Job group list size expected to be = 2 "); Assert.AreEqual(2, triggerGroups.Count, "Trigger group list size expected to be = 2 "); var jobKeys = await sched.GetJobKeys(GroupMatcher <JobKey> .GroupEquals(JobKey.DefaultGroup)); var triggerKeys = await sched.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals(TriggerKey.DefaultGroup)); Assert.AreEqual(1, jobKeys.Count, "Number of jobs expected in default group was 1 "); Assert.AreEqual(1, triggerKeys.Count, "Number of triggers expected in default group was 1 "); jobKeys = await sched.GetJobKeys(GroupMatcher <JobKey> .GroupEquals("g1")); triggerKeys = await sched.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals("g1")); Assert.AreEqual(2, jobKeys.Count, "Number of jobs expected in 'g1' group was 2 "); Assert.AreEqual(2, triggerKeys.Count, "Number of triggers expected in 'g1' group was 2 "); TriggerState s = await sched.GetTriggerState(new TriggerKey("t2", "g1")); Assert.AreEqual(TriggerState.Normal, s, "State of trigger t2 expected to be NORMAL "); await sched.PauseTrigger(new TriggerKey("t2", "g1")); s = await sched.GetTriggerState(new TriggerKey("t2", "g1")); Assert.AreEqual(TriggerState.Paused, s, "State of trigger t2 expected to be PAUSED "); await sched.ResumeTrigger(new TriggerKey("t2", "g1")); s = await sched.GetTriggerState(new TriggerKey("t2", "g1")); Assert.AreEqual(TriggerState.Normal, s, "State of trigger t2 expected to be NORMAL "); var pausedGroups = await sched.GetPausedTriggerGroups(); Assert.AreEqual(0, pausedGroups.Count, "Size of paused trigger groups list expected to be 0 "); await 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() .OfType <TestJob>() .WithIdentity("j4", "g1") .Build(); trigger = TriggerBuilder.Create() .WithIdentity("t4", "g1") .ForJob(job) .StartNow() .WithSimpleSchedule(x => x.RepeatForever().WithIntervalInSeconds(5)) .Build(); await sched.ScheduleJob(job, trigger); pausedGroups = await sched.GetPausedTriggerGroups(); Assert.AreEqual(1, pausedGroups.Count, "Size of paused trigger groups list expected to be 1 "); s = await sched.GetTriggerState(new TriggerKey("t2", "g1")); Assert.AreEqual(TriggerState.Paused, s, "State of trigger t2 expected to be PAUSED "); s = await sched.GetTriggerState(new TriggerKey("t4", "g1")); Assert.AreEqual(TriggerState.Paused, s, "State of trigger t4 expected to be PAUSED"); await sched.ResumeTriggers(GroupMatcher <TriggerKey> .GroupEquals("g1")); s = await sched.GetTriggerState(new TriggerKey("t2", "g1")); Assert.AreEqual(TriggerState.Normal, s, "State of trigger t2 expected to be NORMAL "); s = await sched.GetTriggerState(new TriggerKey("t4", "g1")); Assert.AreEqual(TriggerState.Normal, s, "State of trigger t2 expected to be NORMAL "); pausedGroups = await sched.GetPausedTriggerGroups(); Assert.AreEqual(0, pausedGroups.Count, "Size of paused trigger groups list expected to be 0 "); Assert.IsFalse(await sched.UnscheduleJob(new TriggerKey("foasldfksajdflk")), "Scheduler should have returned 'false' from attempt to unschedule non-existing trigger. "); Assert.IsTrue(await sched.UnscheduleJob(new TriggerKey("t3", "g1")), "Scheduler should have returned 'true' from attempt to unschedule existing trigger. "); jobKeys = await sched.GetJobKeys(GroupMatcher <JobKey> .GroupEquals("g1")); triggerKeys = await sched.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals("g1")); Assert.AreEqual(2, jobKeys.Count, "Number of jobs expected in 'g1' group was 1 "); // job should have been deleted also, because it is non-durable Assert.AreEqual(2, triggerKeys.Count, "Number of triggers expected in 'g1' group was 1 "); Assert.IsTrue(await sched.UnscheduleJob(new TriggerKey("t1")), "Scheduler should have returned 'true' from attempt to unschedule existing trigger. "); jobKeys = await sched.GetJobKeys(GroupMatcher <JobKey> .GroupEquals(JobKey.DefaultGroup)); triggerKeys = await sched.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals(TriggerKey.DefaultGroup)); Assert.AreEqual(1, jobKeys.Count, "Number of jobs expected in default group was 1 "); // job should have been left in place, because it is non-durable Assert.AreEqual(0, triggerKeys.Count, "Number of triggers expected in default group was 0 "); await sched.Shutdown(); }
/// <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); }
public async Task <IEnumerable <JobResponse> > Jobs(JobSearchRequest request) { GroupMatcher <JobKey> matcher = GroupMatcher <JobKey> .AnyGroup(); if (!string.IsNullOrWhiteSpace(request.Group)) { matcher = GroupMatcher <JobKey> .GroupEquals(request.Group.Trim()); } IReadOnlyCollection <JobKey> jobKeys = await _scheduler.GetJobKeys(matcher); // 根据分组查询条件 获取所有JobKey List <JobResponse> items = new List <JobResponse>(); foreach (JobKey key in jobKeys) { // 过滤掉邮件通知配置job,NLog日志文件清除Job if (string.Equals(key.Name, EmailJobKeys.NameKey, StringComparison.InvariantCultureIgnoreCase) || string.Equals(key.Name, NLogJobKey.NameKey, StringComparison.InvariantCultureIgnoreCase)) { continue; } IJobDetail job = await _scheduler.GetJobDetail(key); if (job == null) { continue; } JobResponse item = new JobResponse { Name = job.Key.Name, Group = job.Key.Group, TriggerState = TriggerState.Complete, HttpMethod = job.JobDataMap.GetInt(DataKeys.HttpMethod), RequestUrl = job.JobDataMap.GetString(DataKeys.RequestUrl), TriggerType = job.JobDataMap.GetInt(DataKeys.TriggerType), Interval = job.JobDataMap.GetInt(DataKeys.Interval), IntervalType = job.JobDataMap.GetInt(DataKeys.IntervalType), RepeatCount = job.JobDataMap.GetInt(DataKeys.RepeatCount), Cron = job.JobDataMap.GetString(DataKeys.Cron), RequestBody = job.JobDataMap.GetString(DataKeys.RequestBody), Description = job.Description, CreateTime = job.JobDataMap.GetDateTime(DataKeys.CreateTime), StartTime = job.JobDataMap.GetDateTime(DataKeys.StartTime), EndTime = string.IsNullOrWhiteSpace(job.JobDataMap.GetString(DataKeys.EndTime)) ? null : job.JobDataMap.GetDateTime(DataKeys.EndTime), LastException = job.JobDataMap.GetString(DataKeys.LastException) }; IReadOnlyCollection <ITrigger> triggers = await _scheduler.GetTriggersOfJob(key); ITrigger trigger = triggers.FirstOrDefault(); // 获取当前job关联的第一个 trigger if (trigger != null) { TriggerState triggerState = await _scheduler.GetTriggerState(trigger.Key); // trigger 状态 /****计算时间差***/ DateTime?prevFire = trigger.GetPreviousFireTimeUtc()?.LocalDateTime; DateTime?nextFire = trigger.GetNextFireTimeUtc()?.LocalDateTime; TimeSpan span = TimeSpan.FromSeconds(0); if (prevFire.HasValue && nextFire.HasValue) { span = (nextFire.Value - prevFire.Value); } item.TriggerState = triggerState; item.FirePlan = $"{span.Days}天{span.Hours}小时{span.Minutes}分{span.Seconds}秒"; // 执行频率 item.PrevFireTime = prevFire; item.NextFireTime = nextFire; } ; items.Add(item); } return(items.WhereIf(!string.IsNullOrWhiteSpace(request.Name), x => x.Name.Contains(request.Name.Trim())).OrderByDescending(x => x.CreateTime)); }
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); } }
public async Task TestGetJobKeysWithEquals() { var sched = await CreateScheduler(null); await sched.GetJobKeys(GroupMatcher <JobKey> .GroupEquals("bar")); }
protected async Task ExecutePreProcessCommands( IScheduler scheduler, CancellationToken cancellationToken = default(CancellationToken)) { foreach (string group in jobGroupsToDelete) { if (group.Equals("*")) { Log.Info("Deleting all jobs in ALL groups."); foreach (string groupName in await scheduler.GetJobGroupNames(cancellationToken).ConfigureAwait(false)) { if (!jobGroupsToNeverDelete.Contains(groupName)) { foreach (JobKey key in await scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEquals(groupName), cancellationToken).ConfigureAwait(false)) { await scheduler.DeleteJob(key, cancellationToken).ConfigureAwait(false); } } } } else { if (!jobGroupsToNeverDelete.Contains(group)) { Log.InfoFormat("Deleting all jobs in group: {0}", group); foreach (JobKey key in await scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEquals(group), cancellationToken).ConfigureAwait(false)) { await scheduler.DeleteJob(key, cancellationToken).ConfigureAwait(false); } } } } foreach (string group in triggerGroupsToDelete) { if (group.Equals("*")) { Log.Info("Deleting all triggers in ALL groups."); foreach (string groupName in await scheduler.GetTriggerGroupNames(cancellationToken).ConfigureAwait(false)) { if (!triggerGroupsToNeverDelete.Contains(groupName)) { foreach (TriggerKey key in await scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals(groupName), cancellationToken).ConfigureAwait(false)) { await scheduler.UnscheduleJob(key, cancellationToken).ConfigureAwait(false); } } } } else { if (!triggerGroupsToNeverDelete.Contains(group)) { Log.InfoFormat("Deleting all triggers in group: {0}", group); foreach (TriggerKey key in await scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals(group), cancellationToken).ConfigureAwait(false)) { await scheduler.UnscheduleJob(key, cancellationToken).ConfigureAwait(false); } } } } foreach (JobKey key in jobsToDelete) { if (!jobGroupsToNeverDelete.Contains(key.Group)) { Log.InfoFormat("Deleting job: {0}", key); await scheduler.DeleteJob(key, cancellationToken).ConfigureAwait(false); } } foreach (TriggerKey key in triggersToDelete) { if (!triggerGroupsToNeverDelete.Contains(key.Group)) { Log.InfoFormat("Deleting trigger: {0}", key); await scheduler.UnscheduleJob(key, cancellationToken).ConfigureAwait(false); } } }
protected override void PerformOperation(GroupInput input) { Scheduler.PauseJobs(GroupMatcher <JobKey> .GroupEquals(input.Group)); }
public override void Update(IScheduler scheduler) { this.Scheduler = scheduler; var grps = this.Scheduler.GetJobGroupNames(); this.Jobs = new BindableCollection <IJobDetail>(grps.SelectMany(grp => this.Scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEquals(grp))) .Select(key => this.Scheduler.GetJobDetail(key))); this.NotifyOfPropertyChange(() => this.Jobs); }
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(); } } }
public void TestOverwriteFlag() { // create temp file string tempFileName = XMLSchedulingDataProcessor.QuartzXmlFileName; using (TextWriter writer = new StreamWriter(tempFileName, false)) { using (StreamReader reader = new StreamReader(ReadJobXmlFromEmbeddedResource("SimpleJobTrigger.xml"))) { writer.Write(reader.ReadToEnd()); writer.Flush(); writer.Close(); } } IScheduler scheduler = null; try { StdSchedulerFactory factory = new StdSchedulerFactory(); scheduler = StdSchedulerFactory.GetDefaultScheduler(); // 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(); scheduler.ScheduleJob(job, trigger); XMLSchedulingDataProcessor processor = new XMLSchedulingDataProcessor(new SimpleTypeLoadHelper()); try { 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. Assert.AreEqual(1, scheduler.GetJobKeys(GroupMatcher <JobKey> .GroupEquals("DEFAULT")).Count); Assert.AreEqual(1, scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals("DEFAULT")).Count); job = 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) { scheduler.Shutdown(); } } }
public async Task Action([FromBody] ActionArgs args) { switch (args.Action.ToLower()) { case "shutdown": await Scheduler.Shutdown(); break; case "standby": await Scheduler.Standby(); break; case "start": await Scheduler.Start(); break; case "pause": if (string.IsNullOrEmpty(args.Name)) { await Scheduler.PauseAll(); } else { if (args.Groups == "trigger-groups") { await Scheduler.PauseTriggers(GroupMatcher <TriggerKey> .GroupEquals(args.Name)); } else if (args.Groups == "job-groups") { await Scheduler.PauseJobs(GroupMatcher <JobKey> .GroupEquals(args.Name)); } else { throw new InvalidOperationException("Invalid groups: " + args.Groups); } } break; case "resume": if (string.IsNullOrEmpty(args.Name)) { await Scheduler.ResumeAll(); } else { if (args.Groups == "trigger-groups") { await Scheduler.ResumeTriggers(GroupMatcher <TriggerKey> .GroupEquals(args.Name)); } else if (args.Groups == "job-groups") { await Scheduler.ResumeJobs(GroupMatcher <JobKey> .GroupEquals(args.Name)); } else { throw new InvalidOperationException("Invalid groups: " + args.Groups); } } break; default: throw new InvalidOperationException("Invalid action: " + args.Action); } }
public void Execute(IJobExecutionContext context) { #region 添加脚本任务 ISchedulerFactory schedulerFactory = new StdSchedulerFactory(); IScheduler scheduler = schedulerFactory.GetScheduler(); string jobGroupName = "ScriptJobGroup"; string triGroupName = "ScriptTriGroup"; string jobNamePex = "ScriptJob_"; string triNamePex = "ScriptTri_"; //所有需要运行的脚本 var allScript = AllScript(); var triKeyArr = scheduler.GetTriggerKeys(GroupMatcher <TriggerKey> .GroupEquals("ScriptTriGroup")); //删除触发器,删除这个触发器没有在运行的脚本里 foreach (var t in triKeyArr) { var trigger = scheduler.GetTrigger(t); IJobDetail job = scheduler.GetJobDetail(trigger.JobKey); var tmp = allScript.SingleOrDefault(x => t.Name == triNamePex + x.ID.ToString()); if (tmp == null) { StopTask(Convert.ToInt32(t.Name.Replace(triNamePex, ""))); scheduler.DeleteJob(trigger.JobKey); logger.InfoFormat("脚本服务 移除触发器ID{0}", t.Name); } } foreach (var t in allScript) { try { //新任务 if (triKeyArr.SingleOrDefault(x => x.Name == triNamePex + t.ID.ToString()) == null) { IJobDetail job = JobBuilder.Create <ScriptTaskAddQuartz>() .WithIdentity(new JobKey(jobNamePex + t.ID.ToString(), jobGroupName)) .StoreDurably() .Build(); ICronTrigger trigger = (ICronTrigger)TriggerBuilder.Create() .WithIdentity(new TriggerKey(triNamePex + t.ID.ToString(), triGroupName)) .ForJob(job) .StartNow().WithCronSchedule(t.RUN_WHEN) .Build(); logger.InfoFormat("脚本服务 添加脚本触发器ID{0}", trigger.Key.Name); scheduler.ScheduleJob(job, trigger); } else { ICronTrigger trigger = (ICronTrigger)scheduler.GetTrigger(new TriggerKey(triNamePex + t.ID.ToString(), triGroupName)); IJobDetail job = scheduler.GetJobDetail(trigger.JobKey); if (trigger.CronExpressionString != t.RUN_WHEN) { logger.InfoFormat("脚本服务 修改触发器【{0}】的时间表达式【{1}】为【{2}】", trigger.Key.Name, trigger.CronExpressionString, t.RUN_WHEN); trigger.CronExpressionString = t.RUN_WHEN; scheduler.DeleteJob(trigger.JobKey); scheduler.ScheduleJob(job, trigger); } } } catch (Exception e) { Dictionary <string, object> dicStart = new Dictionary <string, object>(); dicStart.Add("STATUS", "禁用"); FunSqlToClass.UpData <SCRIPT>( ConfigurationManager.AppSettings["dbType"], ConfigurationManager.AppSettings["dbConnSt"], dicStart, string.Format("where ID={0} ", t.ID), ConfigurationManager.AppSettings["dbPrefix"]); logger.InfoFormat("脚本服务 添加脚本触发器任务【{0}】,失败【{1}】", t.CODE, e.Message); } } #endregion #region 运行脚本任务 //获取正在等待的任务 foreach (var task in AllScriptTask()) { try { #region 检测运算实例是否存在,并把结束了的线程终止 QuartzRunStatus nowQrs = new QuartzRunStatus(); IList <QuartzRunStatus> qrs = new List <QuartzRunStatus>(); try { qrs = ProInterface.JSON.EncodeToEntity <IList <QuartzRunStatus> >(System.IO.File.ReadAllText(statusLogPath)); } catch { } //清理2小时还没有远行完的口径 foreach (var t in qrs.Where(x => x.StatusTime.AddHours(2) < DateTime.Now).ToList()) { qrs.Remove(t); } if (qrs == null) { qrs = new List <QuartzRunStatus>(); } nowQrs = qrs.SingleOrDefault(x => x.JobName == "ScriptID_" + task.SCRIPT_ID); if (nowQrs == null) { nowQrs = new QuartzRunStatus(); } //表示该脚本正在运行,则退出 if (nowQrs.IsRun) { continue; } if (qrs.Count > ProInterface.AppSet.ScriptRunMaxNum) { logger.InfoFormat("执行脚本数【{0}】已经超过最大任务数【{1}】了", qrs.Count, ProInterface.AppSet.ScriptRunMaxNum); return; } nowQrs.IsRun = true; nowQrs.JobName = "ScriptID_" + task.SCRIPT_ID; nowQrs.StatusTime = DateTime.Now; if (qrs.SingleOrDefault(x => x.JobName == "ScriptID_" + task.SCRIPT_ID) == null) { qrs.Add(nowQrs); } Fun.WriteAllText(statusLogPath, ProInterface.JSON.DecodeToStr(qrs)); #endregion logger.InfoFormat("执行脚本 开始脚本【{0}】,任务ID【{1}】", task.SCRIPT_ID, task.ID); Dictionary <string, object> dicStart = new Dictionary <string, object>(); dicStart.Add("RUN_STATE", "运行"); dicStart.Add("START_TIME", DateTime.Now); dicStart.Add("RETURN_CODE", null); dicStart.Add("END_TIME", null); dicStart.Add("DISABLE_DATE", null); dicStart.Add("DISABLE_REASON", null); FunSqlToClass.UpData <SCRIPT_TASK>( ConfigurationManager.AppSettings["dbType"], ConfigurationManager.AppSettings["dbConnSt"], dicStart, string.Format("where ID={0} ", task.ID), ConfigurationManager.AppSettings["dbPrefix"]); FunSqlToClass.NonQuery("DELETE FROM YL_SCRIPT_TASK_LOG where SCRIPT_TASK_ID=" + task.ID, ConfigurationManager.AppSettings["dbType"], ConfigurationManager.AppSettings["dbConnSt"], ConfigurationManager.AppSettings["dbPrefix"]); ProServer.Service db = new Service(); ProInterface.ErrorInfo error = new ProInterface.ErrorInfo(); object obj = db.ScriptTaskStart(ref error, Convert.ToInt32(task.ID)); if (error.IsError) { Dictionary <string, object> dic = new Dictionary <string, object>(); dic.Add("RUN_STATE", "停止"); dic.Add("RETURN_CODE", "失败"); dic.Add("END_TIME", DateTime.Now); dic.Add("DISABLE_DATE", DateTime.Now); if (error.Message != null) { if (error.Message.Length > 25) { dic.Add("DISABLE_REASON", error.Message.Substring(0, 25)); } else { dic.Add("DISABLE_REASON", error.Message); } } FunSqlToClass.UpData <SCRIPT_TASK>( ConfigurationManager.AppSettings["dbType"], ConfigurationManager.AppSettings["dbConnSt"], dic, string.Format("where ID={0} ", task.ID), ConfigurationManager.AppSettings["dbPrefix"]); logger.InfoFormat("执行脚本 脚本【{0}】,任务ID【{1}】 出错:{2}", task.SCRIPT_ID, task.ID, error.Message); } else { logger.InfoFormat("执行脚本 结束脚本【{0}】,任务ID【{1}】", task.SCRIPT_ID, task.ID); } } catch (Exception e) { logger.InfoFormat("分析 结束脚本【{0}】,任务ID【{1}】,出错:{2}", task.SCRIPT_ID, task.ID, e.ToString()); } var qrsEnd = ProInterface.JSON.EncodeToEntity <IList <QuartzRunStatus> >(System.IO.File.ReadAllText(statusLogPath)); var nowQrsEnd = qrsEnd.SingleOrDefault(x => x.JobName == "ScriptID_" + task.SCRIPT_ID); if (nowQrsEnd != null) { qrsEnd.Remove(nowQrsEnd); Fun.WriteAllText(statusLogPath, ProInterface.JSON.DecodeToStr(qrsEnd)); } } #endregion }