1、cron 表達(dá)式的基本格式 用過(guò) linux 的應(yīng)該對(duì) cron 有所了解。linux 中可以通過(guò) crontab -e 來(lái)配置定時(shí)任務(wù)。不過(guò),linux 中的 cron 只能精確到分鐘。而我們這里要討論的 Go實(shí)現(xiàn)的 cron 可以精確到秒,除了這點(diǎn)比較大的區(qū)別外,cron 表達(dá)式的基本語(yǔ)法是類似的。(如果使用過(guò) java 中的 Quartz,對(duì) cron 表達(dá)式應(yīng)該比較了解,而且它和這里我們將要討論的 Go 版 cron 很像,也都精確到秒)
cron(計(jì)劃任務(wù)),顧名思義,按照約定的時(shí)間,定時(shí)的執(zhí)行特定的任務(wù)(job)。cron 表達(dá)式 表達(dá)了這種約定。
cron 表達(dá)式代表了一個(gè)時(shí)間集合,使用 6 個(gè)空格分隔的字段表示。
字段名 是否必須 允許的值 允許的特定字符 秒(Seconds) 是 0-59 * / , - 分(Minutes) 是 0-59 * / , - 時(shí)(Hours) 是 0-23 * / , - 日(Day of month) 是 1-31 * / , – ? 月(Month) 是 1-12 or JAN-DEC * / , - 星期(Day of week) 否 0-6 or SUM-SAT * / , – ? 注: 1)月(Month)和星期(Day of week)字段的值不區(qū)分大小寫(xiě),如:SUN、Sun 和 sun 是一樣的。 2)星期 (Day of week)字段如果沒(méi)提供,相當(dāng)于是 *
2、特殊字符說(shuō)明 1)星號(hào)(*) 表示 cron 表達(dá)式能匹配該字段的所有值。如在第5個(gè)字段使用星號(hào)(month),表示每個(gè)月
2)斜線(/) 表示增長(zhǎng)間隔,如第1個(gè)字段(minutes) 值是 3-59/15,表示每小時(shí)的第3分鐘開(kāi)始執(zhí)行一次,之后每隔 15 分鐘執(zhí)行一次(即 3、18、33、48 這些時(shí)間點(diǎn)執(zhí)行),這里也可以表示為:3/15
3)逗號(hào)(,) 用于枚舉值,如第6個(gè)字段值是 MON,WED,FRI,表示 星期一、三、五 執(zhí)行
4)連字號(hào)(-) 表示一個(gè)范圍,如第3個(gè)字段的值為 9-17 表示 9am 到 5pm 直接每個(gè)小時(shí)(包括9和17)
5)問(wèn)號(hào)(?) 只用于 日(Day of month) 和 星期(Day of week),表示不指定值,可以用于代替 *
3、主要類型或接口說(shuō)明 1)Cron:包含一系列要執(zhí)行的實(shí)體;支持暫停【stop】;添加實(shí)體等
type Cron struct { entries []*Entry stop chan struct{} // 控制 Cron 實(shí)例暫停 add chan *Entry // 當(dāng) Cron 已經(jīng)運(yùn)行了,增加新的 Entity 是通過(guò) add 這個(gè) channel 實(shí)現(xiàn)的 snapshot chan []*Entry // 獲取當(dāng)前所有 entity 的快照 running bool // 當(dāng)已經(jīng)運(yùn)行時(shí)為true;否則為false}12345671234567注意,Cron 結(jié)構(gòu)沒(méi)有導(dǎo)出任何成員。
注意:有一個(gè)成員 stop,類型是 struct{},即空結(jié)構(gòu)體。
2)Entry:調(diào)度實(shí)體
type Entry struct { // The schedule on which this job should be run. // 負(fù)責(zé)調(diào)度當(dāng)前 Entity 中的 Job 執(zhí)行 Schedule Schedule // The next time the job will run. This is the zero time if Cron has not been // started or this entry's schedule is unsatisfiable // Job 下一次執(zhí)行的時(shí)間 Next time.Time // The last time this job was run. This is the zero time if the job has never // been run. // 上一次執(zhí)行時(shí)間 PRev time.Time // The Job to run. // 要執(zhí)行的 Job Job Job}12345678910111213141516171819123456789101112131415161718193)Job:每一個(gè)實(shí)體包含一個(gè)需要運(yùn)行的Job 這是一個(gè)接口,只有一個(gè)方法:run
type Job interface { Run()}123123由于 Entity 中需要 Job 類型,因此,我們希望定期運(yùn)行的任務(wù),就需要實(shí)現(xiàn) Job 接口。同時(shí),由于 Job 接口只有一個(gè)無(wú)參數(shù)無(wú)返回值的方法,為了使用方便,作者提供了一個(gè)類型:
type FuncJob func()
它通過(guò)簡(jiǎn)單的實(shí)現(xiàn) Run() 方法來(lái)實(shí)現(xiàn) Job 接口:
func (f FuncJob) Run() { f() }
這樣,任何無(wú)參數(shù)無(wú)返回值的函數(shù),通過(guò)強(qiáng)制類型轉(zhuǎn)換為 FuncJob,就可以當(dāng)作 Job 來(lái)使用了,AddFunc 方法 就是這么做的。
4)Schedule:每個(gè)實(shí)體包含一個(gè)調(diào)度器(Schedule) 負(fù)責(zé)調(diào)度 Job 的執(zhí)行。它也是一個(gè)接口。
type Schedule interface { // Return the next activation time, later than the given time. // Next is invoked initially, and then each time the job is run. // 返回同一 Entity 中的 Job 下一次執(zhí)行的時(shí)間 Next(time.Time) time.Time}123456123456Schedule 的具體實(shí)現(xiàn)通過(guò)解析 Cron 表達(dá)式得到。
庫(kù)中提供了 Schedule 的兩個(gè)具體實(shí)現(xiàn),分別是 SpecSchedule 和 ConstantDelaySchedule。
① SpecSchedule
type SpecSchedule struct { Second, Minute, Hour, Dom, Month, Dow uint64}123123從開(kāi)始介紹的 Cron 表達(dá)式可以容易得知各個(gè)字段的意思,同時(shí),對(duì)各種表達(dá)式的解析也會(huì)最終得到一個(gè) SpecSchedule 的實(shí)例。庫(kù)中的 Parse 返回的其實(shí)就是 SpecSchedule 的實(shí)例(當(dāng)然也就實(shí)現(xiàn)了 Schedule 接口)。
② ConstantDelaySchedule
type ConstantDelaySchedule struct { Delay time.Duration // 循環(huán)的時(shí)間間隔}123123這是一個(gè)簡(jiǎn)單的循環(huán)調(diào)度器,如:每 5 分鐘。注意,最小單位是秒,不能比秒還小,比如 毫秒。
通過(guò) Every 函數(shù)可以獲取該類型的實(shí)例,如:
constDelaySchedule := Every(5e9)
得到的是一個(gè)每 5 秒執(zhí)行一次的調(diào)度器。
4、主要實(shí)例化方法 1) 函數(shù) ① 實(shí)例化 Cron
func New() *Cron { return &Cron{ entries: nil, add: make(chan *Entry), stop: make(chan struct{}), snapshot: make(chan []*Entry), running: false, }}123456789123456789可見(jiàn)實(shí)例化時(shí),成員使用的基本是默認(rèn)值;
② 解析 Cron 表達(dá)式
func Parse(spec string) (_ Schedule, err error)
spec 可以是:
② 成員方法
// 將 job 加入 Cron 中 // 如上所述,該方法只是簡(jiǎn)單的通過(guò) FuncJob 類型強(qiáng)制轉(zhuǎn)換 cmd,然后調(diào)用 AddJob 方法 func (c *Cron) AddFunc(spec string, cmd func()) error
// 將 job 加入 Cron 中 // 通過(guò) Parse 函數(shù)解析 cron 表達(dá)式 spec 的到調(diào)度器實(shí)例(Schedule),之后調(diào)用 c.Schedule 方法 func (c *Cron) AddJob(spec string, cmd Job) error
// 獲取當(dāng)前 Cron 總所有 Entities 的快照 func (c *Cron) Entries() []*Entry
// 通過(guò)兩個(gè)參數(shù)實(shí)例化一個(gè) Entity,然后加入當(dāng)前 Cron 中 // 注意:如果當(dāng)前 Cron 未運(yùn)行,則直接將該 entity 加入 Cron 中; // 否則,通過(guò) add 這個(gè)成員 channel 將 entity 加入正在運(yùn)行的 Cron 中 func (c *Cron) Schedule(schedule Schedule, cmd Job)
// 新啟動(dòng)一個(gè) goroutine 運(yùn)行當(dāng)前 Cron func (c *Cron) Start()
// 通過(guò)給 stop 成員發(fā)送一個(gè) struct{}{} 來(lái)停止當(dāng)前 Cron,同時(shí)將 running 置為 false // 從這里知道,stop 只是通知 Cron 停止,因此往 channel 發(fā)一個(gè)值即可,而不關(guān)心值是多少 // 所以,成員 stop 定義為空 struct func (c *Cron) Stop()
5、使用示例
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注