阅读目录
开始阅读 完整代码下载
Quartz.Net是一个从Java版的Quartz移植过来的定时任务框架,可以非常非常灵活的设置定时任务,IT工程师只需要编写少量代码就可以实现非常复杂的定时任务,比如:每天晚上多个服务器数据同步,游戏里面排行榜定时更新等等。使用之前需要在nuget里引用包Quartz,我这里用的是Quartz 3.2.4
介绍一下Quartz,Net的基本概念,计划者(IScheduler)、工作(IJob)、触发器(Trugger),合起来就是分配给计划者一个工作,在触发器的触发条件下执行这个工作。将要定时执行任务的代码写道实现IJob接口的Execute方法中,触发条件满足的时候就会执行Execute方法。
计划者是执行计划的实例,可以有多个实例同时存在,每个实例之间是相对独立的。需要通过工厂StdSchedulerFactory来创建实例。只用计划者实例启动后里面的任务才会工作。
1 // 初始化IScheduler 2 StdSchedulerFactory factory = new StdSchedulerFactory(); 3 IScheduler scheduler = await factory.GetScheduler(); 4 await scheduler.Start(); //只有启动了,里面的任务才会定时触发
工作是定时执行的动作。我们自定义的工作需要继承自这个IJob接口,需要执行的任务代码放在继承接口的Execute方法里。
1 // 自定义Job 2 public class MyJob : IJob 3 { 4 public async Task Execute(IJobExecutionContext context) 5 { 6 //使用异步任务来实现 7 await Task.Run(() => 8 { 9 Console.WriteLine($"{DateTime.Now}【{Thread.CurrentThread.ManagedThreadId}】:自定义的工作正在执行... ..."); 10 }); 11 } 12 }
1 // 创建Job 2 IJobDetail jobDetail1 = JobBuilder.Create<MyJob>() 3 .WithIdentity("计划者1的myjob任务1", "分组1")//给Job身份 4 .WithDescription("任务的描述,用来查找使用") 5 .Build();
触发器就是定时策略。
1 //创建触发器 2 ITrigger trigger1 = TriggerBuilder.Create() 3 .WithIdentity("计划者1的trigger1", "触发器1组") //给触发器身份 4 .WithDescription("触发器的描述,方便查找") 5 .StartAt(new DateTimeOffset(DateTime.Now.AddSeconds(10))) //.StartNow()都是启动触发器方式 6 .WithCronSchedule("0 0/1 * * * ?") //定时策略,Cron表达式 7 .Build();
1 // 定时触发器 2 ITrigger trigger3 = TriggerBuilder.Create() 3 .WithIdentity("计划者1的trigger3", "触发器1组") 4 .WithSimpleSchedule(x => 5 { 6 x.WithInterval(TimeSpan.FromSeconds(1)) //以毫秒为单位循环 7 //.WithIntervalInSeconds(1) //以秒为单位循环 8 //.WithIntervalInMinutes(1) //以分为单位循环 9 //.WithIntervalInHours(1) //以销售为单位循环 10 //.RepeatForever() //一直重复 11 .WithRepeatCount(10);//重复多少次 12 }).Build();
定时策略(Cron表达式)
1、从左到右有7个位置,分别代表: Seconds秒、Minutes分钟、Hours小时、Day-of-Month月中的天、Month月、Day-of-Week周中的天、Year年(可省略),每个位置可以用范围或者值来表示,例如周可以有:"MON-FRI", "MON, WED, FRI"或者甚至"MON-WED,SAT"。
2、通配符(*)可以被用来表示位置中“每个”可能的值。因此在"Month"中的*表示每个月,而在Day-Of-Week中的*则表示“周中的每一天”。
3、所有位置的值都有特定的合法范围,这些值的合法范围相当明显,例如:秒和分的合法值为0到59,小时的合法范围是0到23,Day-of-Month中值的范围是0到31(需要注意不同的月份中的天数不同)。月份的合法值是0到11。或者用字符串JAN,FEB MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV 及DEC来表示。Days-of-Week可以用1到7来表示(1=星期日)或者用字符串SUN, MON, TUE, WED, THU, FRI 和SAT来表示。
4、'/'字符用来表示值的增量,例如, 如果分钟中放入'0/15',它表示“从0开始,每隔15分钟”,如果在分中使用'3/20',则表示“从第3分钟开始,每隔20分钟”或者另外相同的形式就是'3,23,43'。
5、'?'字符可以用在day-of-month及day-of-week域中,它用来表示“没有指定值”。这对于需要指定一个或者两个域的值而不需要对其他域进行设置来说相当有用。
6、'L'字符可以在day-of-month及day-of-week中使用,这个字符是"last"的简写,但是在两个中的意义不同。例如,在day-of-month中的"L"表示这个月的最后一天,即,一月的31日,非闰年的二月的28日。如果它用在day-of-week中,则表示"7"或者"SAT"。但是如果在day-of-week中,这个字符跟在别的值后面,则表示"当月的最后的周XXX"。例如:"6L" 或者 "FRIL"都表示本月的最后一个周五。当使用'L'选项时,最重要的是不要指定列表或者值范围,否则会导致混乱。
7、'W' 字符用来指定距离给定日最接近的周几(在day-of-week中指定)。例如:如果你为day-of-month指定为"15W",则表示“距离月中15号最近的周几”。
8、'#'表示表示月中的第几个周几。例如:day-of-week域中的"6#3" 或者 "FRI#3"表示“月中第三个周五”。
举一些例子:
例1 – 一个简单的每隔5分钟触发一次的表达式
"0 0/5 * * * ?"
例2 – 在每分钟的10秒后每隔5分钟触发一次的表达式(例如. 10:00:10 am, 10:05:10等.)。
"10 0/5 * * * ?" CronTrigger
例3 – 在每个周三和周五的10:30,11:30,12:30触发的表达式。
"0 30 10-13 ? * WED,FRI" CronTrigger
例4 – 在每个月的5号,20号的8点和10点之间每隔半个小时触发一次且不包括10点,只是8:30,9:00和9:30的表达式。
"0 0/30 8-9 5,20 * ?" 注意,对于单独触发器来说,有些日程需求可能过于复杂而不能用表达式表述,例如:9:00到10:00之间每隔5分钟触发一次,下午1:00到10点每隔20分钟触发一次。这个解决方案就是创建两个触发器,两个触发器都运行相同的任务。
第2节中只是创建了,要想其能执行,还需要添加下面的这句代码,把job和trigger添加给计划者
1 //给计划者添加Job和触发器 2 await scheduler.ScheduleJob(jobDetail1, trigger1);
1 // 完整代码 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 using Quartz; 8 using Quartz.Impl; 9 10 namespace Demo16_QuartZ 11 { 12 public class DispatcherManager 13 { 14 15 public static async Task Init() 16 { 17 //初始化计划者 18 StdSchedulerFactory factory = new StdSchedulerFactory(); 19 IScheduler scheduler = await factory.GetScheduler(); 20 await scheduler.Start(); //只有启动了,里面的任务才会定时触发 21 22 //创建Job 23 IJobDetail jobDetail1 = JobBuilder.Create<MyJob>() 24 .WithIdentity("计划者1的myjob任务1", "分组1")//给Job身份 25 .WithDescription("任务的描述,方便查找") 26 .Build(); 27 28 //创建触发器 29 ITrigger trigger1 = TriggerBuilder.Create() 30 .WithIdentity("计划者1的trigger1", "触发器1组") //给触发器身份 31 .WithDescription("触发器的描述,方便查找") 32 .StartAt(new DateTimeOffset(DateTime.Now.AddSeconds(10))) //.StartNow()都是启动触发器方式 33 .WithCronSchedule("0/5 * * * * ?") //定时策略,Cron表达式 34 .Build(); 35 36 //给计划者添加Job和触发器 37 await scheduler.ScheduleJob(jobDetail1, trigger1); 38 } 39 } 40 }
1 // 调用代码 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 using Quartz; 8 using Quartz.Impl; 9 10 namespace Demo16_QuartZ 11 { 12 public class DispatcherManager 13 { 14 15 public static async Task Init() 16 { 17 //初始化计划者 18 StdSchedulerFactory factory = new StdSchedulerFactory(); 19 IScheduler scheduler = await factory.GetScheduler(); 20 await scheduler.Start(); //只有启动了,里面的任务才会定时触发 21 22 //创建Job 23 IJobDetail jobDetail1 = JobBuilder.Create<MyJob>() 24 .WithIdentity("计划者1的myjob任务1", "分组1")//给Job身份 25 .WithDescription("任务的描述,方便查找") 26 .Build(); 27 28 //创建触发器 29 ITrigger trigger1 = TriggerBuilder.Create() 30 .WithIdentity("计划者1的trigger1", "触发器1组") //给触发器身份 31 .WithDescription("触发器的描述,方便查找") 32 .StartAt(new DateTimeOffset(DateTime.Now.AddSeconds(10))) //.StartNow()都是启动触发器方式 33 .WithCronSchedule("0/5 * * * * ?") //定时策略,Cron表达式 34 .Build(); 35 36 //给计划者添加Job和触发器 37 await scheduler.ScheduleJob(jobDetail1, trigger1); 38 } 39 } 40 }
1 // 创建Job的时候放入参数 2 IJobDetail jobDetail2 = JobBuilder.Create<MyJobWithParameter>() 3 .WithIdentity("计划者1的myjob任务2", "分组1") 4 .Build(); 5 jobDetail2.JobDataMap.Add("person","好好学习、天天向上");
1 // 从Job里取出参数 2 namespace Demo16_QuartZ 3 { 4 public class MyJobWithParameter : IJob 5 { 6 public async Task Execute(IJobExecutionContext context) 7 { 8 await Task.Run(() => 9 { 10 Console.WriteLine($"{DateTime.Now}【{Thread.CurrentThread.ManagedThreadId}】:自定义的工作正在执行... ..."); 11 Console.WriteLine(context.JobDetail.JobDataMap["person"]); 12 }); 13 } 14 } 15 }
1 // 创建Trigger放入参数 2 ITrigger trigger2 = TriggerBuilder.Create() 3 .WithIdentity("计划者1的trigger2", "触发器1组") 4 .StartNow() 5 .WithCronSchedule("2/5 * * * * ?") 6 .Build(); 7 trigger2.JobDataMap.Add("student", "青青河边草、悠悠天不老");
1 // 从Job里取出Trigger放入的参数 2 namespace Demo16_QuartZ 3 { 4 public class MyJobWithParameter : IJob 5 { 6 public async Task Execute(IJobExecutionContext context) 7 { 8 await Task.Run(() => 9 { 10 Console.WriteLine($"{DateTime.Now}【{Thread.CurrentThread.ManagedThreadId}】:自定义的工作正在执行... ..."); 11 Console.WriteLine(context.JobDetail.JobDataMap["person"]); 12 Console.WriteLine(context.Trigger.JobDataMap["student"]); 13 }); 14 } 15 } 16 }
1 // 创建保留数据的Job 2 namespace Demo16_QuartZ 3 { 4 [PersistJobDataAfterExecution] //保留上一次Job运行的数据 5 [DisallowConcurrentExecution] //不允许并发 6 public class MyJobStateFul : IJob 7 { 8 public async Task Execute(IJobExecutionContext context) 9 { 10 await Task.Run(() => 11 { 12 var jobDataMap = context.JobDetail.JobDataMap; 13 Console.WriteLine(jobDataMap["Data"]); 14 jobDataMap.Put("Data", jobDataMap.GetInt("Data") + 1); 15 }); 16 } 17 } 18 }
1 //保存状态的Job 2 IJobDetail jobDetail3 = JobBuilder.Create<MyJobStateFul>() 3 .WithIdentity("计划者1的myjob任务3", "分组1") 4 .Build();
Quzrt-Z自带有日志功能,可以方便的记录日志。
1 // 自定义日志 2 namespace Demo16_QuartZ 3 { 4 public class CustomConsoleLogProvider : ILogProvider 5 { 6 //Logger定义、委托 7 //public delegate bool Logger(LogLevel logLevel, Func<string> messageFunc, Exception exception = null, params object[] formatParameters); 8 public Logger GetLogger(string name) 9 { 10 return (logLevel, messageFunc, exception, formatParameters) => 11 { 12 if(logLevel>=LogLevel.Info && messageFunc!=null) 13 { 14 Console.WriteLine($"【{DateTime.Now.ToLongTimeString()}】【{logLevel}】:{messageFunc()}{string.Join(";", formatParameters.Select(p=>p==null?" ":p.ToString()))}-自定义日志{name}"); 15 } 16 return true; 17 }; 18 } 19 20 public IDisposable OpenMappedContext(string key, object value, bool destructure = false) 21 { 22 throw new NotImplementedException(); 23 } 24 25 public IDisposable OpenNestedContext(string message) 26 { 27 throw new NotImplementedException(); 28 } 29 } 30 }
1 // 使用自定义日志 2 namespace Demo16_QuartZ 3 { 4 public class DispatcherManager 5 { 6 7 public static async Task Init() 8 { 9 10 LogProvider.SetCurrentLogProvider(new CustomConsoleLogProvider()); 11 12 //初始化计划者 13 StdSchedulerFactory factory = new StdSchedulerFactory(); 14 IScheduler scheduler = await factory.GetScheduler(); 15 await scheduler.Start(); //只有启动了,里面的任务才会定时触发 16 17 scheduler.ListenerManager.AddSchedulerListener(new CustomSchedulerListener()); 18 scheduler.ListenerManager.AddJobListener(new CustomJobListener()); 19 scheduler.ListenerManager.AddTriggerListener(new CustomTriggerListener()); 20 21 //创建Job 22 IJobDetail jobDetail1 = JobBuilder.Create<MyJob>() 23 .WithIdentity("计划者1的myjob任务1", "分组1")//给Job身份 24 .WithDescription("任务的描述,方便查找") 25 .Build(); 26 27 //创建带参数的Job 28 IJobDetail jobDetail2 = JobBuilder.Create<MyJobWithParameter>() 29 .WithIdentity("计划者1的myjob任务2", "分组1") 30 .Build(); 31 jobDetail2.JobDataMap.Add("person", "好好学习、天天向上"); 32 33 //保存状态的Job 34 IJobDetail jobDetail3 = JobBuilder.Create<MyJobStateFul>() 35 .WithIdentity("计划者1的myjob任务3", "分组1") 36 .Build(); 37 38 //创建触发器 39 ITrigger trigger1 = TriggerBuilder.Create() 40 .WithIdentity("计划者1的trigger1", "触发器1组") //给触发器身份 41 .WithDescription("触发器的描述,方便查找") 42 .StartAt(new DateTimeOffset(DateTime.Now.AddSeconds(10))) //.StartNow()都是启动触发器方式 43 .WithCronSchedule("0/5 * * * * ?") //定时策略,Cron表达式 44 .Build(); 45 46 //创建带参数的触发器 47 ITrigger trigger2 = TriggerBuilder.Create() 48 .WithIdentity("计划者1的trigger2", "触发器1组") 49 .StartNow() 50 .WithCronSchedule("2/5 * * * * ?") 51 .Build(); 52 trigger2.JobDataMap.Add("student", "青青河边草、悠悠天不老"); 53 54 //定时触发器 55 ITrigger trigger3 = TriggerBuilder.Create() 56 .WithIdentity("计划者1的trigger3", "触发器1组") 57 .WithSimpleSchedule(x => 58 { 59 x.WithInterval(TimeSpan.FromSeconds(1)) //以毫秒为单位循环 60 //.WithIntervalInSeconds(1) //以秒为单位循环 61 //.WithIntervalInMinutes(1) //以分为单位循环 62 //.WithIntervalInHours(1) //以销售为单位循环 63 //.RepeatForever() //一直重复 64 .WithRepeatCount(10);//重复多少次 65 }).Build(); 66 67 //给计划者添加Job和触发器 68 //await scheduler.ScheduleJob(jobDetail1, trigger1); 69 await scheduler.ScheduleJob(jobDetail3, trigger3); 70 } 71 } 72 }
在操作Quart-Z的各个环节添加监听事件,常用来记录日志。继承ISchedulerListener接口,实现方法。
1 // 定义Scheduler监听器 2 using Quartz; 3 using System; 4 using System.Collections.Generic; 5 using System.Linq; 6 using System.Text; 7 using System.Threading; 8 using System.Threading.Tasks; 9 10 namespace Demo16_QuartZ 11 { 12 public class CustomSchedulerListener : ISchedulerListener 13 { 14 public async Task JobAdded(IJobDetail jobDetail, CancellationToken cancellationToken = default) 15 { 16 await Task.Run(() => { Console.WriteLine($"增加了任务:{jobDetail.Description}"); }); 17 } 18 19 public Task JobDeleted(JobKey jobKey, CancellationToken cancellationToken = default) 20 { 21 throw new NotImplementedException(); 22 } 23 24 public Task JobInterrupted(JobKey jobKey, CancellationToken cancellationToken = default) 25 { 26 throw new NotImplementedException(); 27 } 28 29 public Task JobPaused(JobKey jobKey, CancellationToken cancellationToken = default) 30 { 31 throw new NotImplementedException(); 32 } 33 34 public Task JobResumed(JobKey jobKey, CancellationToken cancellationToken = default) 35 { 36 throw new NotImplementedException(); 37 } 38 39 public Task JobScheduled(ITrigger trigger, CancellationToken cancellationToken = default) 40 { 41 throw new NotImplementedException(); 42 } 43 44 public Task JobsPaused(string jobGroup, CancellationToken cancellationToken = default) 45 { 46 throw new NotImplementedException(); 47 } 48 49 public Task JobsResumed(string jobGroup, CancellationToken cancellationToken = default) 50 { 51 throw new NotImplementedException(); 52 } 53 54 public Task JobUnscheduled(TriggerKey triggerKey, CancellationToken cancellationToken = default) 55 { 56 throw new NotImplementedException(); 57 } 58 59 public Task SchedulerError(string msg, SchedulerException cause, CancellationToken cancellationToken = default) 60 { 61 throw new NotImplementedException(); 62 } 63 64 public Task SchedulerInStandbyMode(CancellationToken cancellationToken = default) 65 { 66 throw new NotImplementedException(); 67 } 68 69 public Task SchedulerShutdown(CancellationToken cancellationToken = default) 70 { 71 throw new NotImplementedException(); 72 } 73 74 public Task SchedulerShuttingdown(CancellationToken cancellationToken = default) 75 { 76 throw new NotImplementedException(); 77 } 78 79 public Task SchedulerStarted(CancellationToken cancellationToken = default) 80 { 81 throw new NotImplementedException(); 82 } 83 84 public Task SchedulerStarting(CancellationToken cancellationToken = default) 85 { 86 throw new NotImplementedException(); 87 } 88 89 public Task SchedulingDataCleared(CancellationToken cancellationToken = default) 90 { 91 throw new NotImplementedException(); 92 } 93 94 public Task TriggerFinalized(ITrigger trigger, CancellationToken cancellationToken = default) 95 { 96 throw new NotImplementedException(); 97 } 98 99 public Task TriggerPaused(TriggerKey triggerKey, CancellationToken cancellationToken = default) 100 { 101 throw new NotImplementedException(); 102 } 103 104 public Task TriggerResumed(TriggerKey triggerKey, CancellationToken cancellationToken = default) 105 { 106 throw new NotImplementedException(); 107 } 108 109 public Task TriggersPaused(string triggerGroup, CancellationToken cancellationToken = default) 110 { 111 throw new NotImplementedException(); 112 } 113 114 public Task TriggersResumed(string triggerGroup, CancellationToken cancellationToken = default) 115 { 116 throw new NotImplementedException(); 117 } 118 } 119 }
1 // 创建的时候添加监听器 2 StdSchedulerFactory factory = new StdSchedulerFactory(); 3 IScheduler scheduler = await factory.GetScheduler(); 4 await scheduler.Start(); //只有启动了,里面的任务才会定时触发 5 scheduler.ListenerManager.AddSchedulerListener(new CustomSchedulerListener());
1 // 定义Job监听器 2 namespace Demo16_QuartZ 3 { 4 public class CustomJobListener : IJobListener 5 { 6 public string Name => "CustomJobListener"; 7 //被拒绝执行 8 public async Task JobExecutionVetoed(IJobExecutionContext context, CancellationToken cancellationToken = default) 9 { 10 await Task.Run(() => 11 { 12 //context.JobDetail//job信息 13 //context.Trigger //trigger信息 14 //context.Scheduler //scheduler信息 15 Console.WriteLine("JobExecutionVetoed"); 16 }); 17 } 18 //准备执行 19 public async Task JobToBeExecuted(IJobExecutionContext context, CancellationToken cancellationToken = default) 20 { 21 await Task.Run(() => 22 { 23 //context.JobDetail//job信息 24 //context.Trigger //trigger信息 25 //context.Scheduler //scheduler信息 26 Console.WriteLine("JobExecutionVetoed"); 27 }); 28 } 29 //执行了 30 public async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default) 31 { 32 await Task.Run(() => 33 { 34 //context.JobDetail//job信息 35 //context.Trigger //trigger信息 36 //context.Scheduler //scheduler信息 37 Console.WriteLine("JobExecutionVetoed"); 38 }); 39 } 40 } 41 }
1 // 使用Job监听器 2 scheduler.ListenerManager.AddJobListener(new CustomJobListener());
1 // 定义Trigger监听器 2 namespace Demo16_QuartZ 3 { 4 public class CustomTriggerListener : ITriggerListener 5 { 6 public string Name => "CustomTriggerListener"; 7 8 //Trigger完成 9 public async Task TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode, CancellationToken cancellationToken = default) 10 { 11 await Task.Run(() => "TriggerComplete"); 12 } 13 //解除 14 public async Task TriggerFired(ITrigger trigger, IJobExecutionContext context, CancellationToken cancellationToken = default) 15 { 16 await Task.Run(() => "TriggerFired"); 17 } 18 //失效 19 public async Task TriggerMisfired(ITrigger trigger, CancellationToken cancellationToken = default) 20 { 21 await Task.Run(() => "TriggerMisfired"); 22 } 23 //需要放弃Job? 24 public async Task<bool> VetoJobExecution(ITrigger trigger, IJobExecutionContext context, CancellationToken cancellationToken = default) 25 { 26 await Task.Run(() => "VetoJobExecution"); 27 return false; 28 } 29 } 30 }
1 // 使用Trigger监听器 2 scheduler.ListenerManager.AddTriggerListener(new CustomTriggerListener());
把任务Job和触发器Trigger都写到配置文件,通过配置文件来指定。
1 // 新建Job类库 2 namespace Demo16_QuartZ.Common 3 { 4 public class TestJob : IJob 5 { 6 public async Task Execute(IJobExecutionContext context) 7 { 8 await Task.Run(() => 9 { 10 Console.WriteLine($"{DateTime.Now}【{Thread.CurrentThread.ManagedThreadId}】:自定义的工作正在执行... ..."); 11 }); 12 } 13 } 14 }
新建主程序Demo16-QuartZ.MainApp,主程序如下。
1 // 主程序 2 namespace Demo16_QuartZ.MainApp 3 { 4 class Program 5 { 6 static void Main(string[] args) 7 { 8 StdSchedulerFactory factory = new StdSchedulerFactory(); 9 IScheduler scheduler = factory.GetScheduler().Result; 10 11 //加载配置 12 XMLSchedulingDataProcessor processor = 13 new XMLSchedulingDataProcessor(new SimpleTypeLoadHelper()); 14 var filePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "quartz_jobs.xml"); 15 processor.ProcessFileAndScheduleJobs(filePath, scheduler); 16 17 //加载监听器 18 scheduler.ListenerManager.AddSchedulerListener(new CustomSchedulerListener()); 19 scheduler.ListenerManager.AddJobListener(new CustomJobListener()); 20 scheduler.ListenerManager.AddTriggerListener(new CustomTriggerListener()); 21 22 scheduler.Start(); 23 24 Console.ReadKey(); 25 } 26 } 27 }
1 // 监听程序CustomSchedulerListener 2 namespace Demo16_QuartZ.MainApp 3 { 4 public class CustomSchedulerListener : ISchedulerListener 5 { 6 public async Task JobAdded(IJobDetail jobDetail, CancellationToken cancellationToken = default) 7 { 8 await Task.Run(() => { Console.WriteLine($"增加了任务:{jobDetail.Description}"); }); 9 } 10 11 public async Task JobDeleted(JobKey jobKey, CancellationToken cancellationToken = default) 12 { 13 await Task.Run(() => Console.WriteLine("JobDeleted")); 14 } 15 16 public async Task JobInterrupted(JobKey jobKey, CancellationToken cancellationToken = default) 17 { 18 await Task.Run(() => Console.WriteLine("JobInterrupted")); 19 } 20 21 public async Task JobPaused(JobKey jobKey, CancellationToken cancellationToken = default) 22 { 23 await Task.Run(() => Console.WriteLine("JobPaused")); 24 } 25 26 public async Task JobResumed(JobKey jobKey, CancellationToken cancellationToken = default) 27 { 28 await Task.Run(() => Console.WriteLine("JobResumed")); 29 } 30 31 public async Task JobScheduled(ITrigger trigger, CancellationToken cancellationToken = default) 32 { 33 await Task.Run(() => Console.WriteLine("JobScheduled")); 34 } 35 36 public async Task JobsPaused(string jobGroup, CancellationToken cancellationToken = default) 37 { 38 await Task.Run(() => Console.WriteLine("JobsPaused")); 39 } 40 41 public async Task JobsResumed(string jobGroup, CancellationToken cancellationToken = default) 42 { 43 await Task.Run(() => Console.WriteLine("JobsResumed")); 44 } 45 46 public async Task JobUnscheduled(TriggerKey triggerKey, CancellationToken cancellationToken = default) 47 { 48 await Task.Run(() => Console.WriteLine("JobUnscheduled")); 49 } 50 51 public async Task SchedulerError(string msg, SchedulerException cause, CancellationToken cancellationToken = default) 52 { 53 await Task.Run(() => Console.WriteLine("SchedulerError")); 54 } 55 56 public async Task SchedulerInStandbyMode(CancellationToken cancellationToken = default) 57 { 58 await Task.Run(() => Console.WriteLine("SchedulerInStandbyMode")); 59 } 60 61 public async Task SchedulerShutdown(CancellationToken cancellationToken = default) 62 { 63 await Task.Run(() => Console.WriteLine("SchedulerShutdown")); 64 } 65 66 public async Task SchedulerShuttingdown(CancellationToken cancellationToken = default) 67 { 68 await Task.Run(() => Console.WriteLine("SchedulerShuttingdown")); 69 } 70 71 public async Task SchedulerStarted(CancellationToken cancellationToken = default) 72 { 73 await Task.Run(() => Console.WriteLine("SchedulerStarted")); 74 } 75 76 public async Task SchedulerStarting(CancellationToken cancellationToken = default) 77 { 78 await Task.Run(() => Console.WriteLine("SchedulerStarting")); 79 } 80 81 public async Task SchedulingDataCleared(CancellationToken cancellationToken = default) 82 { 83 await Task.Run(() => Console.WriteLine("SchedulingDataCleared")); 84 } 85 86 public async Task TriggerFinalized(ITrigger trigger, CancellationToken cancellationToken = default) 87 { 88 await Task.Run(() => Console.WriteLine("TriggerFinalized")); 89 } 90 91 public async Task TriggerPaused(TriggerKey triggerKey, CancellationToken cancellationToken = default) 92 { 93 await Task.Run(() => Console.WriteLine("TriggerPaused")); 94 } 95 96 public async Task TriggerResumed(TriggerKey triggerKey, CancellationToken cancellationToken = default) 97 { 98 await Task.Run(() => Console.WriteLine("TriggerResumed")); 99 } 100 101 public async Task TriggersPaused(string triggerGroup, CancellationToken cancellationToken = default) 102 { 103 await Task.Run(() => Console.WriteLine("TriggersPaused")); 104 } 105 106 public async Task TriggersResumed(string triggerGroup, CancellationToken cancellationToken = default) 107 { 108 await Task.Run(() => Console.WriteLine("TriggersResumed")); 109 } 110 } 111 }
1 // 监听程序CustomJobListener 2 namespace Demo16_QuartZ.MainApp 3 { 4 public class CustomJobListener : IJobListener 5 { 6 public string Name => "CustomJobListener"; 7 //被拒绝执行 8 public async Task JobExecutionVetoed(IJobExecutionContext context, CancellationToken cancellationToken = default) 9 { 10 await Task.Run(() => 11 { 12 //context.JobDetail//job信息 13 //context.Trigger //trigger信息 14 //context.Scheduler //scheduler信息 15 Console.WriteLine("JobExecutionVetoed"); 16 }); 17 } 18 //准备执行 19 public async Task JobToBeExecuted(IJobExecutionContext context, CancellationToken cancellationToken = default) 20 { 21 await Task.Run(() => 22 { 23 //context.JobDetail//job信息 24 //context.Trigger //trigger信息 25 //context.Scheduler //scheduler信息 26 Console.WriteLine("JobExecutionVetoed"); 27 }); 28 } 29 //执行了 30 public async Task JobWasExecuted(IJobExecutionContext context, JobExecutionException jobException, CancellationToken cancellationToken = default) 31 { 32 await Task.Run(() => 33 { 34 //context.JobDetail//job信息 35 //context.Trigger //trigger信息 36 //context.Scheduler //scheduler信息 37 Console.WriteLine("JobExecutionVetoed"); 38 }); 39 } 40 } 41 }
1 // 监听程序CustomTriggerListener 2 namespace Demo16_QuartZ.MainApp 3 { 4 public class CustomTriggerListener : ITriggerListener 5 { 6 public string Name => "CustomTriggerListener"; 7 8 //Trigger完成 9 public async Task TriggerComplete(ITrigger trigger, IJobExecutionContext context, SchedulerInstruction triggerInstructionCode, CancellationToken cancellationToken = default) 10 { 11 await Task.Run(() => "TriggerComplete"); 12 } 13 //解除 14 public async Task TriggerFired(ITrigger trigger, IJobExecutionContext context, CancellationToken cancellationToken = default) 15 { 16 await Task.Run(() => "TriggerFired"); 17 } 18 //失效 19 public async Task TriggerMisfired(ITrigger trigger, CancellationToken cancellationToken = default) 20 { 21 await Task.Run(() => "TriggerMisfired"); 22 } 23 //需要放弃Job? 24 public async Task<bool> VetoJobExecution(ITrigger trigger, IJobExecutionContext context, CancellationToken cancellationToken = default) 25 { 26 await Task.Run(() => "VetoJobExecution"); 27 return false; 28 } 29 } 30 }
1 <!--配置文件quartz_jobs.xml--> 2 <?xml version="1.0" encoding="UTF-8"?> 3 <job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0"> 4 <processing-directives> 5 <overwrite-existing-data>true</overwrite-existing-data> 6 </processing-directives> 7 <schedule> 8 <job> 9 <name>testJob</name> 10 <group>myGroup</group> 11 <description>测试任务</description> 12 <job-type>Demo16_QuartZ.Common.TestJob, Demo16_QuartZ.Common</job-type> 13 <durable>true</durable> 14 <recover>false</recover> 15 </job> 16 <trigger> 17 <cron> 18 <name>testTrigger</name> 19 <group>myTriggerGroup</group> 20 <job-name>testJob</job-name> 21 <job-group>myGroup</job-group> 22 <cron-expression>0/5 * * * * ?</cron-expression> 23 <!-- 每隔5秒执行一次--> 24 </cron> 25 </trigger> 26 </schedule> 27 </job-scheduling-data>
为了方便管理,我们这里使用远程可视化管理。我这里使用NET5的MVC项目,还在研究中,以后再更新。
.net 5中配置Quartz集群 https://www.cnblogs.com/shapman/p/14218712.html
官方网站 https://www.quartz-scheduler.net/
官方源码 https://github.com/quartznet/quartznet
CrystalQuartz开源的地址 https://github.com/guryanovev/CrystalQuartz