Quartz.NET 实现了3个具体的触发器类,SimpleTrigger 简单地在某一时间重复执行多少次,NthIncludedDayTrigger 在每一年、月、周的第几天(Nth)执行作业,CronTrigger 使用 Unix 平台下的'cron-like’表达式来实现非常灵活的触发时间。
SimpleTrigger
它有一个起始时间和结束时间,起始时间触发器触发,过了结束时间触发器停止触发。时间间隔 Interval,触发次数 RepeatCount。
如果一个作业,在指定的时间点执行一次,或者间隔时间内重复执行,SimpleTrigger就可以满足这样的要求。简而言之,2005年1月13日11点23分54秒触发,每10分钟触发5次。
显而易见,SimpleTrigger包括开始时间,结束时间,重复次数,间隔。重复次数可以为零,正整数,SimpleTrigger.RepeatIndefinitely常量。间隔时间可以为TimeSpan.Zero,或正的TimeSpan.Value。
注:间隔时间为TimeSpan.Zero时,会导致同时触发(并发)。
SimpleTrigger有几个不同的构造器:
public
SimpleTrigger(
string
name,
string
group, DateTime startTimeUtc, NullableDateTime endTime endTimeUtc,
int
repeatCount, TimeSpan repeatInterval)
SimpleTrigger Example 1 - 从现在开始10分钟后触发一次
SimpleTrigger Example 2 - 每60分钟响应一次,立即执行
SimpleTrigger Example 3 - 每10分钟响应一次,40分钟后开始
SimpleTrigger Example 4 - 2002年3月17日上午10点30分响应,重复5次(共6次触发),每次之间有30分钟间隔
花点时间再看看别的SimpleTrigger构造器,您会发现那个对您最方便。
SimpleTrigger过时触发
MisfirePolicy.SimpleTrigger.FireNow MisfirePolicy.SimpleTrigger.RescheduleNowWithExistin
gRepeatCount MisfirePolicy.SimpleTrigger.RescheduleNowWithRemaini
ngRepeatCount MisfirePolicy.SimpleTrigger.RescheduleNextWithRemain
ingCount MisfirePolicy.SimpleTrigger.RescheduleNextWithExisti
ngCount
如果用“smart policy”,SimpleTrigger会根据SimpleTrigger实例的状态和配置动态选择过时触发策略。SimpleTrigger.UpdateAfterMisfire()方法介绍中,详细解释了动态表现。
CronTrigger
CronTrigger 使用 UNIX 下的“Cron-like” 表达式,实际上用起来感觉它很像正则表达式,可以匹配任意时间,这是体现它灵活性的地方。它的规则如下:
Cron 表达式包括以下 7 个字段(1 个可选)
秒 分 小时 月内日期 月 周内日期 年(可选)
表达式的每个数值域都是一个有最大值和最小值的集合,如:秒域和分钟域的集合是0-59,日期域是1-31,月份域是1-12。注意:秒、分、小时字段是从小到大排序的,这是西方人的习惯,所以在使用的时候要小心,不要颠倒过来。
允许值及对应表见表1。
表1. Cron 表达式允许值及对应表
字段 允许值 允许的特殊字符 秒 0-59 , - * / 分 0-59 , - * / 小时 0-23 , - * / 月内日期 1-31 , - * ? / L W C 月 1-12 或者 JAN-DEC , - * / 周内日期 1-7 或者 SUN-SAT , - * ? / L C # 年(可选) 留空, 1970-2099 , - * /
特殊字符意义对应表见表2。
表2. Cron 表达式特殊字符意义对应表
特殊字符
意义
*
匹配所有的值。如:*在分钟的字段域里表示 每分钟
?
只在日期域和星期域中使用。它被用来指定“非明确的值”
-
指定一个范围。如:“10-12”在小时域意味着“10点、11点、12点”
,
指定几个可选值。如:“MON,WED,FRI”在星期域里表示“星期一、星期三、星期五”
/
指定增量。如:“0/15”在秒域意思是没分钟的0,15,30和45秒。“5/15”在分钟域表示没小时的5,20,35和50。符号“*”在“/”前面(如:*/10)等价于0在“/”前面(如:0/10)
L
表示day-of-month和day-of-week域,但在两个字段中的意思不同,例如day-of-month域中表示一个月的最后一天。如果在day-of-week域表示‘7’或者‘SAT’,如果在day-of-week域中前面加上数字,它表示一个月的最后几天,例如‘6L’就表示一个月的最后一个星期五
W
只允许日期域出现。这个字符用于指定日期的最近工作日。例如:如果你在日期域中写 “15W”,表示:这个月15号最近的工作日。所以,如果15号是周六,则任务会在14号触发。如果15好是周日,则任务会在周一也就是16号触发。如果是在日期域填写“1W”即使1号是周六,那么任务也只会在下周一,也就是3号触发,“W”字符指定的最近工作日是不能够跨月份的。字符“W”只能配合一个单独的数值使用,不能够是一个数字段,如:1-15W是错误的
LW
L和W可以在日期域中联合使用,LW表示这个月最后一周的工作日
#
只允许在星期域中出现。这个字符用于指定本月的某某天。例如:“6#3”表示本月第三周的星期五(6表示星期五,3表示第三周)。“2#1”表示本月第一周的星期一。“4#5”表示第五周的星期三
C
允许在日期域和星期域出现。这个字符依靠一个指定的“日历”。也就是说这个表达式的值依赖于相关的“日历”的计算结果,如果没有“日历”关联,则等价于所有包含的“日历”。如:日期域是“5C”表示关联“日历”中第一天,或者这个月开始的第一天的后5天。星期域是“1C”表示关联“日历”中第一天,或者星期的第一天的后1天,也就是周日的后一天(周一)
示例:
"0 0 0 1 1 ?” 每年元旦1月1日 0 点触发
"0 15 10 * * ? *" 每天上午10:15触发
"0 15 10 * * ? 2005" 2005年的每天上午10:15触发"0 0-5 14 * * ?" 每天下午2点到下午2:05期间的每1分钟触发
"0 10,44 14 ? 3 WED" 每年三月的星期三的下午2:10和2:44触发
"0 15 10 ? * MON-FRI" 周一至周五的上午10:15触发"0 15 10 ? * 6#3" 每月的第三个星期五上午10:15触发
触发器
像Job一样,触发器相对来说还是比较容易实现的。但是要充分利用Quartz.Net,还需要透彻理解触发器的几个自定义选项。早先我们提到过,有几个不同类型的触发器,可以选择不同类型的触发器来满足不同作业的需要。
Calendars
HolidayCalendar cal =
new
HolidayCalendar();
cal.AddExcludedDate(someDate);
sched.AddCalendar(
"myHolidays"
, cal,
false
);
// fire every one hour interval
Trigger trigger = TriggerUtils.MakeHourlyTrigger();
// start on the next even hour
trigger.StartTimeUtc = TriggerUtils.GetEvenHourDate(DateTime.Now);
trigger.Name =
"myTrigger1"
;
trigger.CalendarName =
"myHolidays"
;
// .. schedule job with trigger
// fire every day at 08:00
Trigger trigger2 = TriggerUtils.MakeDailyTrigger(8, 0);
// begin immediately
trigger.StartTimeUtc = DateTime.UtcNow;
trigger2.Name =
"myTrigger2"
;
trigger2.CalendarName =
"myHolidays"
;
// .. schedule job with trigger2
Priority
Note: 当一个Trigger被恢复的时候,也是按照他们原来的优先级来恢复的。
Priority Example
过时触发Misfire Instructions
TriggerUtils - 让Triggers更容易
Trigger Listeners监听器
Trigger能够像Job一样,可以把监听器注册到Trigger中,实现了接口TriggerListener的对象就可以接收到Trigger触发时的通知。
CronTrigger
如果需要像日历一样重复发生的作业调度的话,CronTriggers就比特别指定间隔时间的SimpleTrigger,更有用。
运用CronTrigger, 可以设定的作业调度像,每周五下午,每工作日的上午9点,每周1、2、5的上午9点到10点。
和SimpleTrigger一样, 有效的CronTrigger有一个开始时间,一个当调度不再继续的结束时间,结束时间是可选的。
Cron Expressions表达式
Cron-Expressions是用来配置CronTrigger实例的。 Cron-Expressions是由7个子字符串表达式组成,用来详细描述schedule的。这些表达式以空格分开:
- Seconds
- Minutes
- Hours
- Day-of-Month
- Month
- Day-of-Week
- Year (optional field)
如一个完整的"0 0 12 ? * WED"表示"每周三晚上12"。
所有的字段都可以指定具体的值。这些值需要比较明确,如0-59表示分钟、秒,0-23表达小时。0-31表示日期,但您得指定的月份有多少天哦!月份可以指定为0-11, 或者缩写JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV,DEC。 工作日1-7 (1是星期日),或用字符串SUN, MON, TUE, WED, THU, FRI and SAT表示。
'/'字符可以表示成递增的值。如, 如果分钟的字段上'0/15', 表示每15分钟,从0分钟开始。如果分钟的字段上是'3/20',则表示在一个小时中每20分钟、起点是3。换句话说,在分钟的字段上'3,23,43',与之等效。
'?'字符,可以用在一个月的某天,一个星期的某天。是不特指的意思。当在这两个字段中,不特指的时候很方便使用。下面的CronTriger API中将有详细阐述。
'L'字符串,可以用在一个月的某天,一个星期的某天。是"last"的缩写。但在两个字段中表达的意思是不一样的。例如"L"在月份的某天时,一个月的最后一天,30,31,28。如果在工作日的某天时,只是表示"7"或者"SAT"。但是如果在其他值后面,用在工作日字段中的话,即表示“那个月最后一个周几”。
'W'字符串,可以用来指定一个月的第几天那个工作日。"15W",表示某月的第15天那个工作日。
'#'字符串,可以用来指定一个月的第几个工作日。"6#3" 或者"FRI#3",表示一个月的第3个星期5。.
注:有些调度用一个触发器的话,表达式会很复杂。如上午9-10,以及下午1点到10点没20分钟一次。这种场景适合建立两个简单的触发器,两个触发器都运行同一个作业。
CronTrigger过时触发
下面介绍CronTrigger的过时触发。 这些过时触发定义在常量MisfireInstruction.CronTrigger中:
- DoNothing
- FireOnceNow
所有触发器都有MisfireInstrution.SmartPolicy过时触发, 且作为缺省的过时触发。这种策略'smart policy'可在CronTrigger这里,以理解为 MisfireInstruction.CronTrigger.FireOnceNow。CronTrigger.UpdateAfterMisfire()方法,在后续有更纤细的阐述。
TriggerListeners and JobListeners
Listeners是用来监听在调度作业有执行动作的对象。TriggerListeners用来接收和triggers相关的事件,JobListeners用来接收和作业有关系的事件.
Trigger相关的事件: 触发器触发,触发器过期触发,触发器结束。
ITriggerListener接口
作业相关的时间包括: 作业执行提示,作业结束提示。
IJobListener接口
用自己的Listeners
创建listener很简单, 创建一个继承ITriggerListener或者IJobListener接口的一个对象。Listeners在调度运行时注册,通过Name属性指定的名称。可以注册成"global" 或者 "non-global"。全局listeners接收所有触发器/作业,non-global监听器接收通过GetTriggerListenerNames() 或者 GetJobListenerNames()获得的事件。
listeners在调度运行的时候注册的,不是与作业和触发器一起存放在JobStore中。jobs与triggers,只是存放那些与之相关的坚听器的名称。因此,每次应用运行时,listeners是需要在调度中重新注册的。
向
Scheduler
添加
JobListener
scheduler.AddGlobalJobListener(myJobListener);
or
scheduler.AddJobListener(myJobListener);
常在Quartz.Net中使用,但是如果需要事件提示就随手可见,不需要作业明示的提醒应用。