CronTriggers 通常比 SimpleTrigger 更有用,如果您需要一个基于类似日历的概念而不是根据 SimpleTrigger 的确切指定间隔重复出现的作业触发计划。
使用 CronTrigger,您可以指定触发时间表,例如“每个星期五中午”,或“每个工作日和上午 9:30”,甚至“每周一、周三上午 9:00 到上午 10:00 之间的每 5 分钟” 和星期五”。
即便如此,像 SimpleTrigger 一样,CronTrigger 有一个 startTime 指定计划何时生效,以及一个(可选)endTime 指定何时应该停止计划。
Cron 表达式
Cron-Expressions 用于配置 CronTrigger 的实例。 Cron-Expressions 是实际上由七个子表达式组成的字符串,用于描述计划的各个细节。这些子表达式用空格分隔,并表示:
- 1.秒
- 2.分钟
- 3.小时
- 4.日期
- 5.月
- 6.星期几
- 7.年份(可选字段)
完整的 cron 表达式的一个示例是字符串 0 0 12 ? * WED
- 意思是“每周三中午 12:00”。
单个子表达式可以包含范围和/或列表。例如,前一个示例中的星期几字段(读取为“WED”)可以替换为“MON-FRI”、“MON, WED, FRI”,甚至是“MON-WED,SAT”。
通配符(*
字符)可用于表示该字段的“每个”可能值。因此,前面示例的“月”字段中的 *
字符仅表示“每个月”。 星期几 字段中的 *
显然表示“一周中的每一天”。
所有字段都有一组可以指定的有效值。这些值应该是相当明显的——例如数字 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 和 SAT。
‘/‘ 字符可用于指定值的增量。例如,如果您在“分钟”字段中输入“0/15”,则表示“每 15 分钟,从零分钟开始”。如果您在“分钟”字段中使用“3/20”,则表示“每小时每 20 分钟,从第三分钟开始” - 换句话说,它与在“分钟”中指定“3,23,43”相同场地。
‘?’ 是日期和星期几字段允许使用字符。它用于指定“无特定值”。当您需要在两个字段之一中指定某些内容而不在另一个字段中指定内容时,这很有用。请参阅下面的示例(和 CronTrigger API 文档)进行说明。
‘L’ 字符允许用于日期和星期几字段。这个字符是“last”的简写,但在两个字段中都有不同的含义。例如,日期字段中的值“L”表示“月的最后一天”——非闰年 1 月的第 31 天,2 月的第 28 天。如果单独在星期几字段中使用,它仅表示“7”或“SAT”。但如果在星期几字段中使用另一个值,则表示“本月的最后 xxx 天”——例如“6L”或“FRIL”都表示“本月的最后一个星期五”。使用“L”选项时,重要的是不要指定列表或值范围,因为您会得到令人困惑的结果。
‘W’ 用于指定最接近给定日期的工作日(周一至周五)。例如,如果您将“15W”指定为日期字段的值,则其含义是:“距每月 15 日最近的工作日”。
‘#’ 用于指定该月的“第 n 个”XXX 工作日。例如,星期字段中的“6#3”或“FRI#3”的值表示“每月的第三个星期五”。
示例 Cron 表达式
这里还有一些表达式及其含义的示例 - 您可以在 CronTrigger 的 API 文档中找到更多信息
CronTrigger 示例 1 - 创建一个触发器的表达式,该触发器每 5 分钟触发一次
"0 0/5 * * * ?"
CronTrigger 示例 2 - 创建触发器的表达式,该触发器每 5 分钟触发一次,在该分钟后的 10 秒(即上午 10:00:10、上午 10:05:10 等)。
"10 0/5 * * * ?"
CronTrigger 示例 3 - 创建触发器的表达式,该触发器在每周三和周五的 10:30、11:30、12:30 和 13:30 触发。
"0 30 10-13 ? * WED,FRI"
CronTrigger 示例 4 - 创建触发器的表达式,该触发器在每月 5 日和 20 日上午 8 点到 10 点之间每半小时触发一次。 请注意,触发器不会在上午 10:00 触发,只会在 8:00、8:30、9:00 和 9:30 触发
"0 0/30 8-9 5,20 * ?"
请注意,某些调度要求过于复杂,无法用单个触发器来表达 - 例如“上午 9:00 到上午 10:00 之间每 5 分钟一次,下午 1:00 到晚上 10:00 之间每 20 分钟一次”。 这种情况下的解决方案是简单地创建两个触发器,并注册它们以运行相同的作业。
构建 CronTriggers
CronTrigger 实例是使用 TriggerBuilder
(用于触发器的主要属性)和 WithCronSchedule
扩展方法(用于 CronTrigger 特定属性)构建的。
您还可以使用 CronScheduleBuilder
的静态方法来创建计划。
构建一个触发器,该触发器将在每天上午 8 点到下午 5 点之间每隔一分钟触发一次:
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger3", "group1")
.WithCronSchedule("0 0/2 8-17 * * ?")
.ForJob("myJob", "group1")
.Build();
构建一个每天上午 10:42 触发的触发器:
// we use CronScheduleBuilder's static helper methods here
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger3", "group1")
.WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(10, 42))
.ForJob(myJobKey)
.Build();
或者 -
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger3", "group1")
.WithCronSchedule("0 42 10 * * ?")
.ForJob("myJob", "group1")
.Build();
构建一个触发器,该触发器将在周三上午 10:42 触发,在系统默认的 TimeZone 中:
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger3", "group1")
.WithSchedule(CronScheduleBuilder
.WeeklyOnDayAndHourAndMinute(DayOfWeek.Wednesday, 10, 42)
.InTimeZone(TimeZoneInfo.FindSystemTimeZoneById("Central America Standard Time")))
.ForJob(myJobKey)
.Build();
或者 -
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger3", "group1")
.WithCronSchedule("0 42 10 ? * WED", x => x
.InTimeZone(TimeZoneInfo.FindSystemTimeZoneById("Central America Standard Time")))
.ForJob(myJobKey)
.Build();
CronTrigger 失火指令
以下指令可用于告知 Quartz 在 CronTrigger 发生失火时应该做什么。 (在本教程的 关于触发器的更多信息 部分中介绍了失火情况)。 这些指令被定义为常量(API 文档对它们的行为进行了描述)。 说明包括:
MisfireInstruction.IgnoreMisfirePolicy
MisfireInstruction.CronTrigger.DoNothing
MisfireInstruction.CronTrigger.FireOnceNow
所有触发器都有可用的 MisfireInstrution.SmartPolicy
指令,该指令也是所有触发器类型的默认指令。 CronTrigger 将“智能策略”指令解释为 MisfireInstruction.CronTrigger.FireOnceNow。 CronTrigger.UpdateAfterMisfire()
方法的 API 文档解释了此行为的确切细节。
在构建 CronTriggers 时,您将 misfire 指令指定为 cron 计划的一部分(通过 WithCronSchedule
扩展方法):
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity("trigger3", "group1")
.WithCronSchedule("0 0/2 8-17 * * ?", x => x
.WithMisfireHandlingInstructionFireAndProceed())
.ForJob("myJob", "group1")
.Build();