[TOC]html
<div style="color:gray;text-align:right">shanzm-2020年3月25日 21:28:09</div> <hr style="height:8px;border:none;border-top:5px double black;" />git
好比说,财务系统须要在每月初生成上一个月的财务报表。github
好比说,天天或每周固定时间对数据库更新。数据库
好比说,天天定时发送邮件。express
这些须要在某个预约的时间点周期性的执行某个特定的任务的功能(也就是任务调度),能够使用任务调度框架——Quartz .NET框架
Quartz.NET是一个开源的任务调度框架(做业调度框架),是从Java移植过来的,使用较为普遍!异步
</br> <hr style="height:8px;border:none;border-top:4px double black;" />async
调度器(Scheduler):存放触发器和定时任务,根据触发器执行定时任务ui
触发器(Trigger):决定执行时间,执行间隔,运行次数,故触发器用来告诉调度程序做业何时触发spa
任务(Job):须要定时或是周期性执行的任务
使用流程:
建立调度器-->建立任务-->建立触发器-->Job和Trigger注册到调度器-->启动调度器;
接口/类 | 做用 |
---|---|
IScheduler | 调度器接口 |
IJob | 任务接口,将须要定时执行的方法实如今该接口的Excute方法中 |
IJobDetail | 用于定义Job的实例 |
ITrigger | 触发器接口 |
JobBuilder | 任务构造者:用于建立任务实例 |
TriggerBuilder | 触发器构造者:用于建立触发器实例 |
JobDetailImpl | 实现了IJobDetail类 |
JobKey | 任务名 |
TriggerKey | 触发器名 |
其中触发器的类型
触发器最经常使用的主要有两种:
SimpleTrigger:用于指定任务重复执行的时间间隔
IMutableTrigger:用于指定任务重复执行的具体时间
</br> <hr style="height:8px;border:none;border-top:4px double black;" />
①安装Quartz程序包
当前时间:2020年3月18日 23:20:59,最新版本的Quartz.NET为3.0.7
每次的版本的变化,API变化都好大,因此在这里注明当前的使用版本!
建议使用最新版本,新版本都是异步方法实现的。
NuGet:Install-Package Quartz -Version 3.0.7
②新建TestJob.cs 实现IJob接口
public class TestJob : IJob { public async Task Execute(IJobExecutionContext context) { await Task.Run(() => Console.WriteLine($"{DateTime.Now}:执行任务了……")); } }
<br>
//间隔5s重复一次执行指定的任务 public static async void WithInterval() { //-------1.准备调度者 ISchedulerFactory factory = new StdSchedulerFactory(); //建立调度器工厂 IScheduler scheduler = await factory.GetScheduler(); //建立调度者 //-------2.准备任务 JobBuilder jobBuilder = JobBuilder.Create<TestJob>();//建立任务构造者:JobBuilder IJobDetail job1 = jobBuilder.Build();//建立任务 //-------3.准备触发器 TriggerBuilder triggerBuilder = TriggerBuilder.Create() .StartNow()//当即生效 .WithSimpleSchedule(x=>x.WithIntervalInSeconds(5) .RepeatForever()); //建立触发器构造者:TriggerBuilder ISimpleTrigger trigger = triggerBuilder.WithIdentity("trigger1","group2").Build() as ISimpleTrigger;//建立触发器 //-------4.将任务与触发器添加到调度器中 await scheduler.ScheduleJob(job1, trigger); await scheduler.Start();//开始执行 }
【代码说明】
示例中使用的而是ISimpleTrigger
类型的触发器,能够精准的设置任务重复的时间间隔。
其中的触发器构造者中的
triggerBuilder.StartNow()
表示触发器当即生效
triggerBuilder.StartAt(DateTimeOffset startTimeUtc)
设置触发器生效的时间
triggerBuilder.EndAt(DateTimeOffset startTimeUtc)
设置触发器失效的时间
其中使用WithIntervalInSeconds(5)
表示每五秒触发一次任务
其余的一些按照小时和天的作间隔,以及明确触发次数的方法都简单明确,根据VS的智能提示便可了解,不一一列举于此!
示例中使用RepeatForever()
表示重复无穷次,仍是能够使用WithRepeatCount()
设置重复的次数的。
这里有一个细节问题,好比说,设置执行三次,WithRepeatCount(3)
,可是注意实际会执行4次
<br>
Quartz.NET的接口比较繁多,第一个示例中是使用的最基础的方法,下面代码示例将换一种简写的方式。
//天天按照指定的时间点执行任务 public static async void AtHourAndMinute() { //建立调度器 IScheduler scheduler = await new StdSchedulerFactory().GetScheduler(); //建立任务 //JobDetailImpl job1 = new JobDetailImpl("TestJob1", "group1", typeo(TestJob))//JobDetailImpl是IJobDetail的实现类 //等价于: IJobDetail job1 = JobBuilder.Create<TestJob>().WithIdentity("Testjob1""group1").Build(); //建立触发器 IMutableTrigger trigger2job1 = CronScheduleBuilder.DailyAtHourAndMinut(03, 50).Build();//天天更具某时间点重复触发任务 //将任务和触发器添加到调度器中 trigger2job1.Key = new TriggerKey("trigger1");//注意必定要给触发器命名 await scheduler.ScheduleJob(job1, trigger2job1); //开始执行调度者 await scheduler.Start(); }
【代码说明】
示例中使用的是IMutableTrigger
类型的触发器
经过CronScheduleBuilder
类的静态方法能够设置触发的具体的某一日
设置触发时间为天天的某时某分:DailyAtHourAndMinut(03, 50)
设置触发时间是一周中的哪几天中的几时几分 :AtHourAndMinuteOnGivenDaysOfWeek(int hour , int min, params DayOfWeek[] daysOfWeek)
设置触发时间是每个月中某天某时某分 :CronScheduleBuilder.MonthlyOnDayAndHourAndMinute(int dayOfMonth, int hour, int min).Build()
封装好的一些方法仍是有必定局限的(可是我本身够用的了),关于其余的一些复杂的周期任务,都是能够使用cron expression,使用cron expression能够定义你能想到的全部触发时间和周期
cron expression什么样?怎么用?例如设置触发的时间是:每一年每个月的2点18分40秒CronScheduleBuilder.CronSchedule("40 18 2 ? * * *").WithIdentity("trigger1").Build();
关于cron expression写起来仍是有点麻烦的,能够使用一些在线生成器为咱们自动的生成指望的表达式。
<br>
前面的示例为了简洁的表示Quartz.NET的一些API的使用,
项目中都是把为定时任务,整个的操做流程封装在一个静态方法中,存放在咱们自定义的Job类中
作一个简单的示例:定时发送短信。
自定义Job,实现IJob接口,同时把建立调度器对象,建立触发器和任务封装于其中,做为一个静态方法
class TestJob2 : IJob { public async Task Execute(IJobExecutionContext context) { try { JobDataMap dataMap = context.MergedJobDataMap; string tag = dataMap.GetString("tag"); string title = dataMap.GetString("title"); string content = dataMap.GetString("content"); string description = dataMap.GetString("description"); string tels = dataMap.GetString("tels"); //执行定时任务:模拟发送短信 await Task.Run(() => Console.WriteLine($"发短信:【{tag}】,{title}:{content },{description},电话:{tels}。")); //await context.Scheduler.Shutdown();//表示完成当前的定时任务,关闭调度器 //记入日志 Console.WriteLine("执行了一次定时任务,记入日志"); } catch (Exception ex) { //记入日志Log.Error() Console.WriteLine(ex.Message); } } //将建立定时任务的全部操做封装在此 public static async void SendMessage(string starttime, string cronStr,string tag, string title, string content,string description, string tels) { try { //建立调度器 IScheduler scheduler = await new StdSchedulerFactory().GetScheduler(); //为任务准备参数 DateTime time = DateTime.Parse(starttime); JobDataMap jobData = new JobDataMap() { new KeyValuePair<string, object>("tag", tag), new KeyValuePair<string, object>("title", title), new KeyValuePair<string, object>("content", content), new KeyValuePair<string, object>("description", description), new KeyValuePair<string, object>("tels", tels), }; //建立任务: //注意能够用时间作组名:DateTime.Now.ToLongDateString() IJobDetail job = JobBuilder.Create<TestJob2>() .WithIdentity("Testjob1", "group1") .SetJobData(jobData) .Build(); //建立触发器 ITrigger trigger = TriggerBuilder.Create() .WithIdentity("triger1", "group1") .StartAt(time)//触发器开始时间//.StartNow()如今开始 .WithCronSchedule(cronstr) .Build(); //将任务和触发器添加到调度器中 await scheduler.ScheduleJob(job, trigger); await scheduler.Start(); } catch (Exception ex) { //记入日志 Console.WriteLine(ex.Message); } } }
调用:
public static async void PackageJob() { //从系统当前时间,每隔5s,发送一条短信:【新闻】,新冠病毒,治愈者愈来愈多,普天同庆,10086。 await Task.Run(() => TestJob2.SendMessage(DateTime.Now .ToString(),"/5 * * ? * *","新闻", "新冠病毒", "治愈者愈来愈多", "普天同庆", "10086")); }
【代码说明】
使用JobDataMap
类型存放须要传递到IJob
接口的Excute(IJobExecutionContext context)
方法中
在JobDataMap
中以键值对的方式存放数据,jobDataMao.Add("key",value)
在定义Job的时候,使用触发器对象中的方法jobBuilder.SetJobData(jobData)
将JobDataMap类型的数据传递到任务中
使用JobDataMap dataMap = context.MergedJobDataMap;
获取传递到Excute()中的JobDataMap类型的数据
使用string value = dataMap.GetString("key");
获取数据
由于定时任务的是延时的执行的,因此切记必定要把每一个周期中执行的定时任务记入到日志中,便于维护管理!
注意,由于实现了IJob接口的任务类,其Excute()方法是在一个单独的线程中运行的,因此其异常的处理也在Excute()中使用try……catch……进行处理
BTW:在MVC项目中使用Quartz .NET,直接在Global.asax.cs中的Application_Start()运行封装好的定时任务便可
注意:使用Quartz.NET中的Job,是没法实现任何关于Web的相关操做
<br>
一个调度器中能够调度多个方法
使用 scheduler.ScheduleJob(job,trigger)
将指定的任务和触发器添加到指定的调度器中,能够屡次添加,从而实现一个调度器中调度多个任务
可是有一点要注意:一个任务能够有多个触发器,可是一个触发器只能对应一个任务
调度器能够添加任务,那么就必定是能够移除任务的
//中止触发器 await scheduler.PauseTrigger(triggerKey); //移除触发器 await scheduler.UnscheduleJob(triggerKey); //删除任务 await scheduler.DeleteJob(jobkey);
调度器能够开始运行,那么就必定中止运行:
context.Scheduler.Shutdown();
表示完成当前的定时任务,关闭调度器
Undone……
可参考监听器:JobListeners/TriggerListeners/SchedulerListeners
</br> <hr style="height:8px;border:none;border-top:4px double black;" />
监听器:Quartz.NET使用教程
Quartz(Java)源码:Quartz 源码解析
远程管理及可视化操做: ASP.NET MVC5 实现基于Quartz.NET任务调度
配置方式1:Quartz.NET文档 入门教程
配置方式2:Quartz.Net定时任务简单实用(实例)
Cron Expression:Cron Expression Generator
封装任务和传参:NET做业调度(定时任务)-Quartz.Net
原文出处:https://www.cnblogs.com/shanzhiming/p/12570677.html