譯者注:
目錄在這 Quartz.NET 3.x 教程
原文在這 Lesson 6: CronTrigger
如果你需要一個類似日歷概念而不是像 SimpleTrigger 那樣指定間隔來調度作業觸發, 那么 CronTrigger 通常比 SimpleTrigger 更有用.
使用 CronTrigger, 你可以指定調度觸發時間, 比如 "每周五的中午", "每周日的上午9:30", 甚至是 "每周一, 周三, 周五的上午9:00到10:00之間每5分鍾執行一次".
既然如此, 像 SimpleTrigger 一樣, CronTrigger 也有一個開始時間來指定調度何時生效, 還有一個 (可選) 結束時間來指定調度應該何時終止.
Cron 表達式
Cron 表達式用於配置 CronTrigger 的實例. Cron 表達式實際上是由七個子表達式組成的字符串, 她們描述了調度的各個細節. 這些子表達式用空格分隔,從左往右依次表示:
- 秒
- 分鍾
- 時
- 日
- 月
- 星期幾
- 年 (可選字段)
一個完整的 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分鍾, 從0分鍾開始". 如果你在 "分鍾" 字段中使用 "3/20", 則表示 "一小時內每20分鍾, 從第3分鍾開始", - 亦或在分鍾字段中指定 "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分鍾一次". 這種需求場景的解決辦法是簡單的創建2個觸發器, 並注冊她們來運行同一個作業.
構建 CronTriggers
CronTrigger 實例是使用 TriggerBuilder (用於觸發器的主屬性) 和 WithCronSchedule 擴展方法 (用於 CronTrigger 的特定屬性) 來構建的.
你還可以使用 CronScheduleBuilder 的靜態方法來構建調度.
構建一個觸發器其在每天上午8點到下午8點的每一分鍾會觸發一次:
trigger = TriggerBuilder.Create()
.WithIdentity("trigger3", "group1")
.WithCronSchedule("0 0/2 8-17 * * ?")
.ForJob("myJob", "group1")
.Build();
構建一個觸發器其會在每天上午 10:42 觸發一次:
// 這里我們使用 CronScheduleBuilder 的靜態助手方法
trigger = TriggerBuilder.Create()
.WithIdentity("trigger3", "group1")
.WithSchedule(CronScheduleBuilder.DailyAtHourAndMinute(10, 42))
.ForJob(myJobKey)
.Build();
或者 -
trigger = TriggerBuilder.Create()
.WithIdentity("trigger3", "group1")
.WithCronSchedule("0 42 10 * * ?")
.ForJob("myJob", "group1")
.Build();
構建一個觸發器其會在除系統的默認時區以外的周三上午 10:42 觸發:
trigger = TriggerBuilder.Create()
.WithIdentity("trigger3", "group1")
.WithSchedule(CronScheduleBuilder
.WeeklyOnDayAndHourAndMinute(DayOfWeek.Wednesday, 10, 42)
.InTimeZone(TimeZoneInfo.FindSystemTimeZoneById("Central America Standard Time")))
.ForJob(myJobKey)
.Build();
或者 -
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
所有觸發器都可以使用 Misfireinstruction.SmartPolicy 指令, 並且此指令也是所有觸發器類型的默認指令. CronTrigger 將 MisfireInstruction.CronTrigger.FireOnceNow 作為 '智能策略' 指令. CronTrigger.UpdateAfterMisfire() 方法的API文檔解釋了此行為的確切細節.
當構建 ConTrigger 時, 你可以指定啞火指令作為 cron 調度的一部分 (通過 WithCronSchedule 擴展方法):
trigger = TriggerBuilder.Create()
.WithIdentity("trigger3", "group1")
.WithCronSchedule("0 0/2 8-17 * * ?", x => x
.WithMisfireHandlingInstructionFireAndProceed())
.ForJob("myJob", "group1")
.Build();