Quartz.Net
一、简单的Quartz程序
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Quartz; using Quartz.Impl; using Quartz.Listener; using Quartz.Impl.Matchers; using System.Threading; namespace ConsoleApp3 { class Program { static void Main(string[] args) { //scheduler [10 +1 都开启了,只不过都是等待状态] var scheduler = StdSchedulerFactory.GetDefaultScheduler().Result; //[start 会让 调度线程 启动,从jobstore中获取快要执行的trigger,然后获取trigger关联的job进行执行。] scheduler.Start(); //job var job = JobBuilder.Create<JobTest>().Build(); //trigger var trigger = TriggerBuilder.Create().WithSimpleSchedule(x => x .WithIntervalInSeconds(1)//1s钟执行一次 .RepeatForever()//重复执行 .Build()).Build(); //添加监听 scheduler.ListenerManager.AddJobListener(new MyJobListener(), GroupMatcher<JobKey>.AnyGroup()); //开始调度 scheduler.ScheduleJob(job, trigger); Console.ReadLine(); } //面向AOP public class MyJobListener : IJobListener { public string Name => "test"; //job开始执行之前调用 public async Task JobExecutionVetoed(IJobExecutionContext context, CancellationToken cancellationToken = default(CancellationToken)) { Console.WriteLine("JobExecutionVetoed"); } //job每次执行之后调用 public async Task JobToBeExecuted(IJobExecutionContext context, CancellationToken cancellationToken = default(CancellationToken)) { Console.WriteLine("JobToBeExecuted"); } //job执行结束之后调用 public async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default(CancellationToken)) { Console.WriteLine("JobWasExecuted"); } } } public class JobTest : IJob { public async Task Execute(IJobExecutionContext context) { Console.WriteLine("asd"); } } }
二、 quartz的五大构件
1. Scheduler [一个大容器]
2. job
3. trigger
4. SimpleThreadPool [最终的执行都是要委托给线程池]
10[WorkThread] + 1 [调度线程 QuartzSchedulerThread] => QuarzThread
SimpleThreadPool 默认是10个thread,是在thread上面进行的封装,不是线程池线程。。。
QuartzSchedulerThread => public override void Run()
5. JobStore =>DbStore,RAMStore
timeTriggers 用于获取最近的trigger的。
三、Job详解 【JobBuilder】
var job = JobBuilder.Create<HelloJob>().Build();
在JobBuilder中执行执行的Action有四种方法。。。 Create 和 OfType
1. Create<T>
写代码方便。。
2. Type类型
后期绑定。。。。
Action不是来自解决方案的。。。 可能你要执行的Action来自于其他的团队,对方所做的事情就是实现一下IJob接口就可以了。。。
我们拿到这个Dll,做反射,直接把job丢给scheduler。。。。
3,StoreDurably方法
设置job是否持久化
默认情况下: 一旦job没有相对应的trigger,那么这个job会被删除。。。
如果一对一的情况下,trigger删除,job也会被删除。。。
所有的Job,Trigger 都是在RAMJobStore里面。。。
4,UsingJobData / SetJobData 都是给一个Job添加附加信息。。。
JobDataMap 就是一个字典,用于添加多个信息。。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Quartz; using Quartz.Impl; using Quartz.Listener; using Quartz.Impl.Matchers; using System.Threading; namespace ConsoleApp3 { class Program { static void Main(string[] args) { //scheduler [10 +1 都开启了,只不过都是等待状态] var scheduler = StdSchedulerFactory.GetDefaultScheduler().Result; //[start 会让 调度线程 启动,从jobstore中获取快要执行的trigger,然后获取trigger关联的job进行执行。] scheduler.Start(); //job var job = JobBuilder.Create<JobTest>() .StoreDurably(true) .UsingJobData("username","hunter")//都是给一个Job添加附加信息 .Build(); //trigger var trigger = TriggerBuilder.Create().WithSimpleSchedule(x => x .WithIntervalInSeconds(1)//1s钟执行一次 .RepeatForever()//重复执行 .Build()).Build(); //添加监听 scheduler.ListenerManager.AddJobListener(new MyJobListener(), GroupMatcher<JobKey>.AnyGroup()); //开始调度 scheduler.ScheduleJob(job, trigger); Console.ReadLine(); } //面向AOP public class MyJobListener : IJobListener { public string Name => "test"; //job开始执行之前调用 public async Task JobExecutionVetoed(IJobExecutionContext context, CancellationToken cancellationToken = default(CancellationToken)) { Console.WriteLine("JobExecutionVetoed"); } //job每次执行之后调用 public async Task JobToBeExecuted(IJobExecutionContext context, CancellationToken cancellationToken = default(CancellationToken)) { Console.WriteLine("JobToBeExecuted"); } //job执行结束之后调用 public async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default(CancellationToken)) { Console.WriteLine("JobWasExecuted"); } } } public class JobTest : IJob { public async Task Execute(IJobExecutionContext context) { //获取附加信息 Console.WriteLine(context.MergedJobDataMap["username"]); } } }
5,WithIdentity: 如果没有制定,那么系统会给一个Guid的标识
if (key == null) { key = new JobKey(Guid.NewGuid().ToString(), null); }
四、TriggerBuilder
1. StartAt,EndAt,StartNow Trigger触发的起始时间和结束时间
DateTimeOffset有时区概念,DateTime没有时区的概念
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Quartz; using Quartz.Impl; using Quartz.Listener; using Quartz.Impl.Matchers; using System.Threading; namespace ConsoleApp3 { class Program { static void Main(string[] args) { //scheduler [10 +1 都开启了,只不过都是等待状态] var scheduler = StdSchedulerFactory.GetDefaultScheduler().Result; //[start 会让 调度线程 启动,从jobstore中获取快要执行的trigger,然后获取trigger关联的job进行执行。] scheduler.Start(); //job var job = JobBuilder.Create<JobTest>() .StoreDurably(true) .UsingJobData("username","hunter")//都是给一个Job添加附加信息 .Build(); Console.WriteLine("开始"); //trigger var trigger = TriggerBuilder.Create() .StartAt(DateTimeOffset.Now.AddSeconds(1))//开始执行时间 .EndAt(DateTimeOffset.Now.AddSeconds(5))//执行结束时间 .WithSimpleSchedule(x => x .WithIntervalInSeconds(1)//1s钟执行一次 .RepeatForever()//重复执行 .Build()).Build(); //添加监听 scheduler.ListenerManager.AddJobListener(new MyJobListener(), GroupMatcher<JobKey>.AnyGroup()); //开始调度 scheduler.ScheduleJob(job, trigger); Console.ReadLine(); } //面向AOP public class MyJobListener : IJobListener { public string Name => "test"; //job开始执行之前调用 public async Task JobExecutionVetoed(IJobExecutionContext context, CancellationToken cancellationToken = default(CancellationToken)) { Console.WriteLine("JobExecutionVetoed"); } //job每次执行之后调用 public async Task JobToBeExecuted(IJobExecutionContext context, CancellationToken cancellationToken = default(CancellationToken)) { Console.WriteLine("JobToBeExecuted"); } //job执行结束之后调用 public async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default(CancellationToken)) { Console.WriteLine("JobWasExecuted"); } } } public class JobTest : IJob { public async Task Execute(IJobExecutionContext context) { //获取附加信息 Console.WriteLine(context.MergedJobDataMap["username"]); } } }
2,其他一些方法
.ForJob(job)//在定义Trigger的时候,就可以将对应关系做起来
.UsingJobData("aa","abc")//给Job添加附加信息
.WithPriority(1)//默认优先级【5】(优先级数字越大,优先级越高)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Quartz; using Quartz.Impl; using Quartz.Listener; using Quartz.Impl.Matchers; using System.Threading; namespace ConsoleApp3 { class Program { static void Main(string[] args) { //scheduler [10 +1 都开启了,只不过都是等待状态] var scheduler = StdSchedulerFactory.GetDefaultScheduler().Result; //[start 会让 调度线程 启动,从jobstore中获取快要执行的trigger,然后获取trigger关联的job进行执行。] scheduler.Start(); //job var job = JobBuilder.Create<JobTest>() .StoreDurably(true) .UsingJobData("username","hunter")//都是给一个Job添加附加信息 .Build(); Console.WriteLine("开始"); //trigger var trigger = TriggerBuilder.Create() .StartAt(DateTimeOffset.Now.AddSeconds(1))//开始执行时间 .EndAt(DateTimeOffset.Now.AddSeconds(5))//执行结束时间 .ForJob(job)//在定义Trigger的时候,就可以将对应关系做起来 .UsingJobData("aa","abc")//给Job添加附加信息 .WithPriority(1)//默认优先级【5】(优先级数字越大,优先级越高) .WithSimpleSchedule(x => x .WithIntervalInSeconds(1)//1s钟执行一次 .RepeatForever()//重复执行 .Build()).Build(); //添加监听 scheduler.ListenerManager.AddJobListener(new MyJobListener(), GroupMatcher<JobKey>.AnyGroup()); //开始调度 scheduler.ScheduleJob(job, trigger); Console.ReadLine(); } //面向AOP public class MyJobListener : IJobListener { public string Name => "test"; //job开始执行之前调用 public async Task JobExecutionVetoed(IJobExecutionContext context, CancellationToken cancellationToken = default(CancellationToken)) { Console.WriteLine("JobExecutionVetoed"); } //job每次执行之后调用 public async Task JobToBeExecuted(IJobExecutionContext context, CancellationToken cancellationToken = default(CancellationToken)) { Console.WriteLine("JobToBeExecuted"); } //job执行结束之后调用 public async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default(CancellationToken)) { Console.WriteLine("JobWasExecuted"); } } } public class JobTest : IJob { public async Task Execute(IJobExecutionContext context) { //获取附加信息 Console.WriteLine(context.MergedJobDataMap["aa"]); } } }
五、四大trigger调度器
1,Simplescheduler
特点:只能在时分秒上做轮询
RepeatForever() 指定触发器将无限重复 WithInterval(TimeSpan timeSpan) 指定重复间隔(以毫秒为单位) WithIntervalInHours(int hours) 指定重复间隔(以小时为单位) WithIntervalInMinutes(int minutes) 指定重复间隔(以分钟为单位) WithIntervalInSeconds(int seconds) 以秒为单位指定重复间隔 WithRepeatCount(int repeatCount) 重复执行次数(repeatCount+1)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Quartz; using Quartz.Impl; using Quartz.Listener; using Quartz.Impl.Matchers; using System.Threading; namespace ConsoleApp3 { class Program { static void Main(string[] args) { //scheduler [10 +1 都开启了,只不过都是等待状态] var scheduler = StdSchedulerFactory.GetDefaultScheduler().Result; //[start 会让 调度线程 启动,从jobstore中获取快要执行的trigger,然后获取trigger关联的job进行执行。] scheduler.Start(); //job var job = JobBuilder.Create<JobTest>().Build(); Console.WriteLine("开始"); //trigger var trigger = TriggerBuilder.Create().WithSimpleSchedule(x => x .WithIntervalInSeconds(1) .RepeatForever() .Build()).Build(); //开始调度 scheduler.ScheduleJob(job, trigger); Console.ReadLine(); } } public class JobTest : IJob { private static int index = 0; public async Task Execute(IJobExecutionContext context) { //记录当前时间,记录“scheduler”调度时间 ,记录 下一次触发时间 Console.WriteLine("index={0}, current={1},schedulertime={2},nexttime={3}", index++, DateTime.Now, context.ScheduledFireTimeUtc?.LocalDateTime, context.NextFireTimeUtc?.LocalDateTime); } } }
2, CalendarIntervalSchedule
特点:和日历相关的轮询(1天执行一次,一周执行一次,一个月执行一次,一年执行一次)
WithInterval(int interval, IntervalUnit unit) 指定重复间隔 WithIntervalInDays(int intervalInDays) 指定重复间隔(按天) WithIntervalInHours(int intervalInHours) 指定重复间隔(按小时) WithIntervalInMinutes(int intervalInMinutes) 指定重复间隔(按分钟) WithIntervalInMonths(int intervalInMonths) 指定重复间隔(按月) WithIntervalInSeconds(int intervalInSeconds) 指定重复间隔(按秒) WithIntervalInWeeks(int intervalInWeeks) 指定重复间隔(按星期) WithIntervalInYears(int intervalInYears) 指定重复间隔(按年)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Quartz; using Quartz.Impl; using Quartz.Listener; using Quartz.Impl.Matchers; using System.Threading; namespace ConsoleApp3 { class Program { static void Main(string[] args) { //scheduler [10 +1 都开启了,只不过都是等待状态] var scheduler = StdSchedulerFactory.GetDefaultScheduler().Result; //[start 会让 调度线程 启动,从jobstore中获取快要执行的trigger,然后获取trigger关联的job进行执行。] scheduler.Start(); //job var job = JobBuilder.Create<JobTest>().Build(); Console.WriteLine("开始"); //trigger var trigger = TriggerBuilder.Create().WithCalendarIntervalSchedule(x => x .WithIntervalInWeeks(2)//每两周执行一次 .Build()).Build(); //开始调度 scheduler.ScheduleJob(job, trigger); Console.ReadLine(); } } public class JobTest : IJob { private static int index = 0; public async Task Execute(IJobExecutionContext context) { //记录当前时间,记录“scheduler”调度时间 ,记录 下一次触发时间 Console.WriteLine("index={0}, current={1},schedulertime={2},nexttime={3}", index++, DateTime.Now, context.ScheduledFireTimeUtc?.LocalDateTime, context.NextFireTimeUtc?.LocalDateTime); } } }
3,DailyTimeIntervalScheduleBuilder
OnMondayThroughFriday() 周一至周五执行 OnSaturdayAndSunday() 周六和周日执行
OnEveryDay() 一周所有日子 WithInterval(int interval, IntervalUnit unit) 指定要生成的触发器的时间单位和时间间隔。 WithIntervalInHours(int intervalInHours) 指定重复间隔(按天) WithIntervalInMinutes(int intervalInMinutes) 指定重复间隔(按分钟) WithIntervalInSeconds(int intervalInSeconds) 指定重复间隔(按秒) StartingDailyAt(TimeOfDay.HourAndMinuteOfDay(8, 00) 开始执行时间 EndingDailyAt(TimeOfDay.HourAndMinuteOfDay(20, 00) 结束时间
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Quartz; using Quartz.Impl; using Quartz.Listener; using Quartz.Impl.Matchers; using System.Threading; namespace ConsoleApp3 { class Program { static void Main(string[] args) { //scheduler [10 +1 都开启了,只不过都是等待状态] var scheduler = StdSchedulerFactory.GetDefaultScheduler().Result; //[start 会让 调度线程 启动,从jobstore中获取快要执行的trigger,然后获取trigger关联的job进行执行。] scheduler.Start(); //job var job = JobBuilder.Create<JobTest>().Build(); Console.WriteLine("开始"); //30分钟检测一次,8点-20点 //trigger var trigger = TriggerBuilder.Create().WithDailyTimeIntervalSchedule(x => x .OnEveryDay()//没天执行 .StartingDailyAt(TimeOfDay.HourAndMinuteOfDay(8,0))//开始执行时间 .EndingDailyAt(TimeOfDay.HourAndMinuteOfDay(20,0))//结束执行时间 .WithIntervalInMinutes(30)//不管什么时候执行的此程序,都是每30分钟整点执行一次(例如8:30,13:30) .Build()).Build(); //开始调度 scheduler.ScheduleJob(job, trigger); Console.ReadLine(); } } public class JobTest : IJob { private static int index = 0; public async Task Execute(IJobExecutionContext context) { index++; //记录当前时间,记录“scheduler”调度时间 ,记录 下一次触发时间 Console.WriteLine("index={0}, current={1},schedulertime={2},nexttime={3}", index, DateTime.Now, context.ScheduledFireTimeUtc?.LocalDateTime, context.NextFireTimeUtc?.LocalDateTime); } } }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Quartz; using Quartz.Impl; using Quartz.Listener; using Quartz.Impl.Matchers; using System.Threading; namespace ConsoleApp3 { class Program { static void Main(string[] args) { //scheduler [10 +1 都开启了,只不过都是等待状态] var scheduler = StdSchedulerFactory.GetDefaultScheduler().Result; //[start 会让 调度线程 启动,从jobstore中获取快要执行的trigger,然后获取trigger关联的job进行执行。] scheduler.Start(); //job var job = JobBuilder.Create<JobTest>().Build(); Console.WriteLine("开始"); //每天凌晨2点跑一次 //trigger var trigger = TriggerBuilder.Create().WithDailyTimeIntervalSchedule(x => x .OnEveryDay()//没天执行 .StartingDailyAt(TimeOfDay.HourAndMinuteOfDay(2,0))//开始执行时间 .EndingDailyAt(TimeOfDay.HourAndMinuteOfDay(2,1))//结束执行时间 .WithIntervalInMinutes(30)//巧妙设计,是程序每天只执行一次 .Build()).Build(); //注意做一个问题:在测试的时候先调整好计算机时间,在run此程序 //如果先run程序,在调整时间,会有问题 //开始调度 scheduler.ScheduleJob(job, trigger); Console.ReadLine(); } } public class JobTest : IJob { private static int index = 0; public async Task Execute(IJobExecutionContext context) { index++; //记录当前时间,记录“scheduler”调度时间 ,记录 下一次触发时间 Console.WriteLine("index={0}, current={1},schedulertime={2},nexttime={3}", index, DateTime.Now, context.ScheduledFireTimeUtc?.LocalDateTime, context.NextFireTimeUtc?.LocalDateTime); } } }
5,WithCronSchedule
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Quartz; using Quartz.Impl; using Quartz.Listener; using Quartz.Impl.Matchers; using System.Threading; namespace ConsoleApp3 { class Program { static void Main(string[] args) { //scheduler [10 +1 都开启了,只不过都是等待状态] var scheduler = StdSchedulerFactory.GetDefaultScheduler().Result; //[start 会让 调度线程 启动,从jobstore中获取快要执行的trigger,然后获取trigger关联的job进行执行。] scheduler.Start(); //job var job = JobBuilder.Create<JobTest>().Build(); Console.WriteLine("开始"); //trigger var trigger = TriggerBuilder.Create().WithCronSchedule("* * * ? * MON").Build(); //注意做一个问题:在测试的时候先调整好计算机时间,在run此程序 //如果先run程序,在调整时间,会有问题 //开始调度 scheduler.ScheduleJob(job, trigger); Console.ReadLine(); } } public class JobTest : IJob { private static int index = 0; public async Task Execute(IJobExecutionContext context) { index++; //记录当前时间,记录“scheduler”调度时间 ,记录 下一次触发时间 Console.WriteLine("index={0}, current={1},schedulertime={2},nexttime={3}", index, DateTime.Now, context.ScheduledFireTimeUtc?.LocalDateTime, context.NextFireTimeUtc?.LocalDateTime); } } }
Cron表达式
quartz中的cron表达式和Linux下的很类似,比如 "/5 * * ? * * *" 这样的7位表达式,最后一位年非必选。
表达式从左到右,依此是秒、分、时、月第几天、月、周几、年。下面表格是要遵守的规范:
字段名 | 允许的值 | 允许的特殊字符 |
---|---|---|
Seconds | 0-59 | , - * / |
Minutes | 0-59 | , - * / |
Hours | 0-23 | , - * / |
Day of month | 1-31 | , - * ? / L W |
Month | 1-12 or JAN-DEC | , - * / |
Day of week | 1-7 or SUN-SAT | , - * ? / L # |
Year | 空, 1970-2099 | , - * / |
星期一 MON
星期二 TUE
星期三 WED
星期四 THU
星期五 FRI
星期六 SAT
星期天 SUN
特殊字符 | 解释 |
, | 或的意思。例:分钟位 5,10 即第5分钟或10分都触发。 |
/ | a/b。 a:代表起始时间,b频率时间。 例; 分钟位 3/5, 从第三分钟开始,每5分钟执行一次。 |
* | 频率。 即每一次波动。 例;分钟位 * 即表示每分钟 |
- | 区间。 例: 分钟位 5-10 即5到10分期间。 |
? | 任意值 。 即每一次波动。只能用在DayofMonth和DayofWeek,二者冲突。指定一个另一个一个要用? |
L | 表示最后。 只能用在DayofMonth和DayofWeek,4L即最后一个星期三 |
W | 工作日。 表示最后。 只能用在DayofWeek |
# | 4#2。 只能用DayofMonth。 某月的第二个星期三 |
实例:
每天8-20点间隔28分钟执行一次:0 0/28 8-20 * * ?"
间隔10秒跑一次:0/10 * 8-20 * * ?
每天8-20天,30分钟执行一次: 0 0/30 8-20 * * ?
周一到周五凌晨2点执行: 0 0 2 ? * MON-FRI 执行一次
”0 0 10,14,16 * * ?" 每天10点,14点,16点 触发。
"0 0/5 14,18 * * ?" 每天14点或18点中,每5分钟触发 。
"0 4/15 14-18 * * ?" 每天14点到18点期间, 从第四分钟触发,每15分钟一次。
"0 15 10 ? * 6L" 每月的最后一个星期五上午10:15触发。
六、操作案例
1,trigger先绑定job,然后在执行
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Quartz; using Quartz.Impl; using Quartz.Listener; using Quartz.Impl.Matchers; using System.Threading; namespace ConsoleApp3 { class Program { static void Main(string[] args) { Console.WriteLine("开始"); //scheduler [10 +1 都开启了,只不过都是等待状态] var scheduler = StdSchedulerFactory.GetDefaultScheduler().Result; //[start 会让 调度线程 启动,从jobstore中获取快要执行的trigger,然后获取trigger关联的job进行执行。] scheduler.Start(); //job var job = JobBuilder.Create<JobTest>() .StoreDurably(true) .Build(); scheduler.AddJob(job, true); //trigger var trigger = TriggerBuilder.Create().ForJob(job) .WithCronSchedule("* * * * * ?").Build(); //使用这句话的前提是job必须是持久化的,否则只能使用下面那句话 scheduler.ScheduleJob(trigger); //scheduler.ScheduleJob(job,trigger); Console.ReadLine(); } } public class JobTest : IJob { private static int index = 0; public async Task Execute(IJobExecutionContext context) { index++; //记录当前时间,记录“scheduler”调度时间 ,记录 下一次触发时间 Console.WriteLine("index={0}, current={1},schedulertime={2},nexttime={3}", index, DateTime.Now, context.ScheduledFireTimeUtc?.LocalDateTime, context.NextFireTimeUtc?.LocalDateTime); } } }
2,job操作
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
List<JobDetailImpl> jobList = new List<JobDetailImpl>(); //第一步:获取所有的job信息 var jobKeySet = scheduler.GetJobKeys(GroupMatcher<JobKey>.AnyGroup()); foreach (var jobKey in jobKeySet) { var jobDetail = (JobDetailImpl)scheduler.GetJobDetail(jobKey); jobList.Add(jobDetail); } var json = JsonConvert.SerializeObject(jobList.Select(i => new { i.Name, i.Group, i.Durable, i.JobDataMap, i.Description, TriggerList = string.Join(",", scheduler.GetTriggersOfJob(new JobKey(i.Name, i.Group)) .Select(m => m.Key.ToString())) }));
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
var exists = scheduler.CheckExists(new JobKey(jobRequest.JobName, jobRequest.JobGroupName)); if (exists && !jobRequest.IsEdit) { return Json("已经存在同名的Job,请更换!"); } var assemblyName = jobRequest.JobFullClass.Split('.')[0]; var fullName = jobRequest.JobFullClass; var dllpath = Request.MapPath(string.Format("~/bin/{0}.dll", assemblyName)); //需要执行的job名称 var jobClassName = Assembly.LoadFile(dllpath) .CreateInstance(jobRequest.JobFullClass); //第一种方式: var job = JobBuilder.Create(jobClassName.GetType()).StoreDurably(true) .WithIdentity(jobRequest.JobName, jobRequest.JobGroupName) .WithDescription(jobRequest.Description) .Build(); scheduler.AddJob(job, true); //第二种方式:获取job信息,再更新实体。。。 var jobdetail = scheduler.GetJobDetail(new JobKey(jobRequest.JobName, jobRequest.JobGroupName));
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//job暂停,所有关联的trigger也必须暂停 scheduler.PauseJob(new JobKey(jobName, groupName));
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
scheduler.ResumeJob(new JobKey(jobName, groupName));
2,trigger操作
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
List<CronTriggerImpl> triggerList = new List<CronTriggerImpl>(); //第一步:获取所有的trigger信息 var triggerKeys = scheduler.GetTriggerKeys(GroupMatcher<TriggerKey>.AnyGroup()); foreach (var triggerkey in triggerKeys) { var triggerDetail = (CronTriggerImpl)scheduler.GetTrigger(triggerkey); triggerList.Add(triggerDetail); } var json = JsonConvert.SerializeObject(triggerList.Select(i => new { i.FullName, i.FullJobName, i.CronExpressionString, JobClassName = scheduler.GetJobDetail(i.JobKey).JobType.FullName, StartFireTime = i.StartTimeUtc.LocalDateTime.ToString("yyyy-MM-dd HH:mm:ss"), PrevFireTime = i.GetPreviousFireTimeUtc()?.LocalDateTime.ToString("yyyy-MM-dd HH:mm:ss"), NextFireTime = i.GetNextFireTimeUtc()?.LocalDateTime.ToString("yyyy-MM-dd HH:mm:ss"), TriggerStatus = scheduler.GetTriggerState(new TriggerKey(i.Name, i.Group)).ToString(), i.Priority, i.Description, i.Name, i.Group }));
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
var exists = scheduler.CheckExists(new TriggerKey(triggerRequest.TriggerName, triggerRequest.TriggerGroupName)); if (exists) { return Json("已经存在同名的trigger,请更换!"); } var forJobName = triggerRequest.ForJobName.Split('.'); var trigger = TriggerBuilder.Create().ForJob(forJobName[1], forJobName[0]) .WithIdentity(triggerRequest.TriggerName, triggerRequest.TriggerGroupName) .WithCronSchedule(triggerRequest.CronExpress) .WithDescription(triggerRequest.Description) .Build(); scheduler.ScheduleJob(trigger);
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//暂停 “某一个trigger” scheduler.PauseTrigger(new TriggerKey(name, group));
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//恢复 “某一个trigger” scheduler.ResumeTrigger(new TriggerKey(name, group));
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
scheduler.UnscheduleJob(new TriggerKey(name, group));
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
//编辑Trigger var forJobName = triggerRequest.ForJobName.Split('.'); var trigger = TriggerBuilder.Create().ForJob(forJobName[1], forJobName[0]) .WithIdentity(triggerRequest.TriggerName, triggerRequest.TriggerGroupName) .WithCronSchedule(triggerRequest.CronExpress) .WithDescription(triggerRequest.Description) .Build(); //编辑trigger操作 scheduler.RescheduleJob(new TriggerKey(triggerRequest.TriggerName, triggerRequest.TriggerGroupName), trigger);
3,scheduler操作
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
var meta = scheduler.GetMetaData();
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
if (scheduler.InStandbyMode) { //只有暂停的状态,才能重新开启 scheduler.Start(); }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
if (scheduler.IsStarted) { //暂停scheduler scheduler.Standby(); }
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
if (scheduler.IsStarted || scheduler.InStandbyMode) { //暂停scheduler scheduler.Shutdown(); }
4,整个demo
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using Newtonsoft.Json; using Quartz; using Quartz.Impl; using Quartz.Impl.Matchers; using Quartz.Impl.Triggers; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Web; using System.Web.Mvc; using WebApplication1.Entitys; namespace WebApplication1.Controllers { [RoutePrefix("quartz")] public class QuartzController : Controller { static IScheduler scheduler = null; static QuartzController() { scheduler = StdSchedulerFactory.GetDefaultScheduler(); scheduler.Start(); } [Route("index")] public ActionResult Index() { return View(); } //查询job [Route("joblist")] public JsonResult JobList() { List<JobDetailImpl> jobList = new List<JobDetailImpl>(); //第一步:获取所有的job信息 var jobKeySet = scheduler.GetJobKeys(GroupMatcher<JobKey>.AnyGroup()); foreach (var jobKey in jobKeySet) { var jobDetail = (JobDetailImpl)scheduler.GetJobDetail(jobKey); jobList.Add(jobDetail); } var json = JsonConvert.SerializeObject(jobList.Select(i => new { i.Name, i.Group, i.Durable, i.JobDataMap, i.Description, TriggerList = string.Join(",", scheduler.GetTriggersOfJob(new JobKey(i.Name, i.Group)) .Select(m => m.Key.ToString())) })); return Json(json); } //添加job [Route("addjob")] public JsonResult AddJob(JobRequestEntity jobRequest) { try { var exists = scheduler.CheckExists(new JobKey(jobRequest.JobName, jobRequest.JobGroupName)); if (exists && !jobRequest.IsEdit) { return Json("已经存在同名的Job,请更换!"); } var assemblyName = jobRequest.JobFullClass.Split('.')[0]; var fullName = jobRequest.JobFullClass; var dllpath = Request.MapPath(string.Format("~/bin/{0}.dll", assemblyName)); //需要执行的job名称 var jobClassName = Assembly.LoadFile(dllpath) .CreateInstance(jobRequest.JobFullClass); //第一种方式: var job = JobBuilder.Create(jobClassName.GetType()).StoreDurably(true) .WithIdentity(jobRequest.JobName, jobRequest.JobGroupName) .WithDescription(jobRequest.Description) .Build(); scheduler.AddJob(job, true); //第二种方式:获取job信息,再更新实体。。。 var jobdetail = scheduler.GetJobDetail(new JobKey(jobRequest.JobName, jobRequest.JobGroupName)); return Json("1"); } catch (Exception ex) { throw; } } //暂停job(可恢复) [Route("pausejob")] public JsonResult PauseJob(string jobName, string groupName) { try { //job暂停,所有关联的trigger也必须暂停 scheduler.PauseJob(new JobKey(jobName, groupName)); return Json(1); } catch (Exception ex) { throw; } } //恢复job [Route("resumejob")] public JsonResult ResumeJob(string jobName, string groupName) { try { scheduler.ResumeJob(new JobKey(jobName, groupName)); return Json(1); } catch (Exception ex) { throw; } } //删除job [Route("removejob")] public JsonResult RemoveJob(string jobName, string groupName) { try { var isSuccess = scheduler.DeleteJob(new JobKey(jobName, groupName)); return Json(isSuccess); } catch (Exception ex) { throw; } } //trigger查询 [Route("triggerlist")] public JsonResult TriggerList() { List<CronTriggerImpl> triggerList = new List<CronTriggerImpl>(); //第一步:获取所有的trigger信息 var triggerKeys = scheduler.GetTriggerKeys(GroupMatcher<TriggerKey>.AnyGroup()); foreach (var triggerkey in triggerKeys) { var triggerDetail = (CronTriggerImpl)scheduler.GetTrigger(triggerkey); triggerList.Add(triggerDetail); } var json = JsonConvert.SerializeObject(triggerList.Select(i => new { i.FullName, i.FullJobName, i.CronExpressionString, JobClassName = scheduler.GetJobDetail(i.JobKey).JobType.FullName, StartFireTime = i.StartTimeUtc.LocalDateTime.ToString("yyyy-MM-dd HH:mm:ss"), PrevFireTime = i.GetPreviousFireTimeUtc()?.LocalDateTime.ToString("yyyy-MM-dd HH:mm:ss"), NextFireTime = i.GetNextFireTimeUtc()?.LocalDateTime.ToString("yyyy-MM-dd HH:mm:ss"), TriggerStatus = scheduler.GetTriggerState(new TriggerKey(i.Name, i.Group)).ToString(), i.Priority, i.Description, i.Name, i.Group })); return Json(json); } //添加trigger [Route("addtrigger")] public JsonResult AddTrigger(TriggerRequestEntity triggerRequest) { try { var exists = scheduler.CheckExists(new TriggerKey(triggerRequest.TriggerName, triggerRequest.TriggerGroupName)); if (exists) { return Json("已经存在同名的trigger,请更换!"); } var forJobName = triggerRequest.ForJobName.Split('.'); var trigger = TriggerBuilder.Create().ForJob(forJobName[1], forJobName[0]) .WithIdentity(triggerRequest.TriggerName, triggerRequest.TriggerGroupName) .WithCronSchedule(triggerRequest.CronExpress) .WithDescription(triggerRequest.Description) .Build(); scheduler.ScheduleJob(trigger); return Json("1"); } catch (Exception ex) { throw; } } //暂停trigger(可恢复) [Route("pausetrigger")] public JsonResult PauseTrigger(string name, string group) { try { //暂停 “某一个trigger” scheduler.PauseTrigger(new TriggerKey(name, group)); return Json("1"); } catch (Exception ex) { throw; } } //恢复trigger [Route("resumetrigger")] public JsonResult ResumeTrigger(string name, string group) { try { //恢复 “某一个trigger” scheduler.ResumeTrigger(new TriggerKey(name, group)); return Json("1"); } catch (Exception ex) { throw; } } //删除trigger [Route("removetrigger")] public JsonResult RemoveTrigger(string name, string group) { try { scheduler.UnscheduleJob(new TriggerKey(name, group)); return Json("1"); } catch (Exception ex) { throw; } } //编辑trigger [Route("edittrigger")] public JsonResult EditTrigger(TriggerRequestEntity triggerRequest) { try { //编辑Trigger var forJobName = triggerRequest.ForJobName.Split('.'); var trigger = TriggerBuilder.Create().ForJob(forJobName[1], forJobName[0]) .WithIdentity(triggerRequest.TriggerName, triggerRequest.TriggerGroupName) .WithCronSchedule(triggerRequest.CronExpress) .WithDescription(triggerRequest.Description) .Build(); //编辑trigger操作 scheduler.RescheduleJob(new TriggerKey(triggerRequest.TriggerName, triggerRequest.TriggerGroupName), trigger); return Json("1"); } catch (Exception ex) { throw; } } //获取scheduler元数据信息 [Route("getmeta")] public JsonResult GetMeta() { try { var meta = scheduler.GetMetaData(); var json = JsonConvert.SerializeObject(meta); return Json(json); } catch (Exception ex) { throw; } } /// <summary> /// 恢复scheduler /// </summary> /// <returns></returns> [Route("resumescheduler")] public JsonResult ResumeScheduler() { try { if (scheduler.InStandbyMode) { //只有暂停的状态,才能重新开启 scheduler.Start(); } return Json(1); } catch (Exception ex) { throw; } } /// <summary> /// 暂停scheduler /// </summary> /// <returns></returns> [Route("pausescheduler")] public JsonResult PauseScheduler() { try { if (scheduler.IsStarted) { //暂停scheduler scheduler.Standby(); } return Json(1); } catch (Exception ex) { throw; } } /// <summary> /// 关闭scheduler /// </summary> /// <returns></returns> [Route("shutdownscheduler")] public JsonResult ShutDownScheduler() { try { if (scheduler.IsStarted || scheduler.InStandbyMode) { //暂停scheduler scheduler.Shutdown(); } return Json(1); } catch (Exception ex) { throw; } } } }
下载地址:https://pan.baidu.com/s/1uQMuQEvsky1poiBzg1H3JA
七、六大calendar排除
1,DailyCalendar
【适合在某一天的时间段上做“减法操作”】
可以动态的排除某天的某些时间段
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Quartz; using Quartz.Impl; using Quartz.Listener; using Quartz.Impl.Matchers; using System.Threading; using Quartz.Impl.Calendar; namespace ConsoleApp3 { class Program { static void Main(string[] args) { Console.WriteLine("开始"); //scheduler [10 +1 都开启了,只不过都是等待状态] var scheduler = StdSchedulerFactory.GetDefaultScheduler().Result; //[start 会让 调度线程 启动,从jobstore中获取快要执行的trigger,然后获取trigger关联的job进行执行。] scheduler.Start(); //job var job = JobBuilder.Create<JobTest>() .StoreDurably(true) .Build(); scheduler.AddJob(job, true); //trigger var trigger = TriggerBuilder.Create().ForJob(job) .ModifiedByCalendar("daily") .WithCronSchedule("* * * * * ?").Build(); //每天20点到21点不要执行 var daily = new DailyCalendar(DateBuilder.DateOf(20, 0, 0).DateTime, DateBuilder.DateOf(21, 0, 0).DateTime); scheduler.AddCalendar("daily", daily, true, true); scheduler.ScheduleJob(trigger); Console.ReadLine(); } } public class JobTest : IJob { private static int index = 0; public async Task Execute(IJobExecutionContext context) { index++; //记录当前时间,记录“scheduler”调度时间 ,记录 下一次触发时间 Console.WriteLine("index={0}, current={1},schedulertime={2},nexttime={3}", index, DateTime.Now, context.ScheduledFireTimeUtc?.LocalDateTime, context.NextFireTimeUtc?.LocalDateTime); } } }
2,WeeklyCalendar
【适合以星期几的维度上做“减法操作”】
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Quartz; using Quartz.Impl; using Quartz.Listener; using Quartz.Impl.Matchers; using System.Threading; using Quartz.Impl.Calendar; namespace ConsoleApp3 { class Program { static void Main(string[] args) { Console.WriteLine("开始"); //scheduler [10 +1 都开启了,只不过都是等待状态] var scheduler = StdSchedulerFactory.GetDefaultScheduler().Result; //[start 会让 调度线程 启动,从jobstore中获取快要执行的trigger,然后获取trigger关联的job进行执行。] scheduler.Start(); //job var job = JobBuilder.Create<JobTest>() .StoreDurably(true) .Build(); scheduler.AddJob(job, true); //trigger var trigger = TriggerBuilder.Create().ForJob(job) .ModifiedByCalendar("calendar") .WithCronSchedule("* * * * * ?").Build(); //每周五不执行 WeeklyCalendar calendar = new WeeklyCalendar(); calendar.SetDayExcluded(DayOfWeek.Friday, true); scheduler.AddCalendar("calendar", calendar, true, true); scheduler.ScheduleJob(trigger); Console.ReadLine(); } } public class JobTest : IJob { private static int index = 0; public async Task Execute(IJobExecutionContext context) { index++; //记录当前时间,记录“scheduler”调度时间 ,记录 下一次触发时间 Console.WriteLine("index={0}, current={1},schedulertime={2},nexttime={3}", index, DateTime.Now, context.ScheduledFireTimeUtc?.LocalDateTime, context.NextFireTimeUtc?.LocalDateTime); } } }
3,HolidayCalendar
【适合当年的某一天不能执行】
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Quartz; using Quartz.Impl; using Quartz.Listener; using Quartz.Impl.Matchers; using System.Threading; using Quartz.Impl.Calendar; namespace ConsoleApp3 { class Program { static void Main(string[] args) { Console.WriteLine("开始"); //scheduler [10 +1 都开启了,只不过都是等待状态] var scheduler = StdSchedulerFactory.GetDefaultScheduler().Result; //[start 会让 调度线程 启动,从jobstore中获取快要执行的trigger,然后获取trigger关联的job进行执行。] scheduler.Start(); //job var job = JobBuilder.Create<JobTest>() .StoreDurably(true) .Build(); scheduler.AddJob(job, true); //trigger var trigger = TriggerBuilder.Create().ForJob(job) .ModifiedByCalendar("calendar") .WithCronSchedule("* * * * * ?").Build(); //指定某一天不能执行 //6月16号不要执行 var calendar = new HolidayCalendar(); calendar.AddExcludedDate(DateTime.Now); scheduler.AddCalendar("calendar", calendar, true, true); scheduler.ScheduleJob(trigger); Console.ReadLine(); } } public class JobTest : IJob { private static int index = 0; public async Task Execute(IJobExecutionContext context) { index++; //记录当前时间,记录“scheduler”调度时间 ,记录 下一次触发时间 Console.WriteLine("index={0}, current={1},schedulertime={2},nexttime={3}", index, DateTime.Now, context.ScheduledFireTimeUtc?.LocalDateTime, context.NextFireTimeUtc?.LocalDateTime); } } }
4,MonthlyCalendar
【适合某个月中的某一天不能执行】
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Quartz; using Quartz.Impl; using Quartz.Listener; using Quartz.Impl.Matchers; using System.Threading; using Quartz.Impl.Calendar; namespace ConsoleApp3 { class Program { static void Main(string[] args) { Console.WriteLine("开始"); //scheduler [10 +1 都开启了,只不过都是等待状态] var scheduler = StdSchedulerFactory.GetDefaultScheduler().Result; //[start 会让 调度线程 启动,从jobstore中获取快要执行的trigger,然后获取trigger关联的job进行执行。] scheduler.Start(); //job var job = JobBuilder.Create<JobTest>() .StoreDurably(true) .Build(); scheduler.AddJob(job, true); //trigger var trigger = TriggerBuilder.Create().ForJob(job) .ModifiedByCalendar("calendar") .WithCronSchedule("* * * * * ?").Build(); //每月20号不要执行 var calendar = new MonthlyCalendar(); calendar.SetDayExcluded(20, true); scheduler.AddCalendar("calendar", calendar, true, true); scheduler.ScheduleJob(trigger); Console.ReadLine(); } } public class JobTest : IJob { private static int index = 0; public async Task Execute(IJobExecutionContext context) { index++; //记录当前时间,记录“scheduler”调度时间 ,记录 下一次触发时间 Console.WriteLine("index={0}, current={1},schedulertime={2},nexttime={3}", index, DateTime.Now, context.ScheduledFireTimeUtc?.LocalDateTime, context.NextFireTimeUtc?.LocalDateTime); } } }
5,AnnualCalendar
【适合每年指定的某一天不能执行】
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Quartz; using Quartz.Impl; using Quartz.Listener; using Quartz.Impl.Matchers; using System.Threading; using Quartz.Impl.Calendar; namespace ConsoleApp3 { class Program { static void Main(string[] args) { Console.WriteLine("开始"); //scheduler [10 +1 都开启了,只不过都是等待状态] var scheduler = StdSchedulerFactory.GetDefaultScheduler().Result; //[start 会让 调度线程 启动,从jobstore中获取快要执行的trigger,然后获取trigger关联的job进行执行。] scheduler.Start(); //job var job = JobBuilder.Create<JobTest>() .StoreDurably(true) .Build(); scheduler.AddJob(job, true); //trigger var trigger = TriggerBuilder.Create().ForJob(job) .ModifiedByCalendar("calendar") .WithCronSchedule("* * * * * ?").Build(); //指定月份中的某一天不能执行 var calendar = new AnnualCalendar(); calendar.SetDayExcluded(DateTime.Now, true); scheduler.AddCalendar("calendar", calendar, true, true); scheduler.ScheduleJob(trigger); Console.ReadLine(); } } public class JobTest : IJob { private static int index = 0; public async Task Execute(IJobExecutionContext context) { index++; //记录当前时间,记录“scheduler”调度时间 ,记录 下一次触发时间 Console.WriteLine("index={0}, current={1},schedulertime={2},nexttime={3}", index, DateTime.Now, context.ScheduledFireTimeUtc?.LocalDateTime, context.NextFireTimeUtc?.LocalDateTime); } } }
6,CronCalendar
【字符串表达式来排除某一天,某一个月份,某一年都可以】
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Quartz; using Quartz.Impl; using Quartz.Listener; using Quartz.Impl.Matchers; using System.Threading; using Quartz.Impl.Calendar; namespace ConsoleApp3 { class Program { static void Main(string[] args) { Console.WriteLine("开始"); //scheduler [10 +1 都开启了,只不过都是等待状态] var scheduler = StdSchedulerFactory.GetDefaultScheduler().Result; //[start 会让 调度线程 启动,从jobstore中获取快要执行的trigger,然后获取trigger关联的job进行执行。] scheduler.Start(); //job var job = JobBuilder.Create<JobTest>() .StoreDurably(true) .Build(); scheduler.AddJob(job, true); //trigger var trigger = TriggerBuilder.Create().ForJob(job) .ModifiedByCalendar("calendar") .WithCronSchedule("* * * * * ?").Build(); //4月21号不要执行 var calendar = new CronCalendar("* * * 21 4 ?"); scheduler.AddCalendar("calendar", calendar, true, true); scheduler.ScheduleJob(trigger); Console.ReadLine(); } } public class JobTest : IJob { private static int index = 0; public async Task Execute(IJobExecutionContext context) { index++; //记录当前时间,记录“scheduler”调度时间 ,记录 下一次触发时间 Console.WriteLine("index={0}, current={1},schedulertime={2},nexttime={3}", index, DateTime.Now, context.ScheduledFireTimeUtc?.LocalDateTime, context.NextFireTimeUtc?.LocalDateTime); } } }