Go 学习笔记(77)— Go 第三方库之 cronexpr(解析 crontab 表达式,定时任务)
cronexpr 支持的比 Linux 自身的 crontab 更詳細,可以精確到秒級別。
?
1. 實現方式
cronexpr 表達式從前到后的順序如下所示:
字段類型 是否為必須字段 允許的值 允許的特殊字符
---------- ---------- -------------- --------------------------
Seconds No 0-59 * / , -
Minutes Yes 0-59 * / , -
Hours Yes 0-23 * / , -
Day of month Yes 1-31 * / , - L W
Month Yes 1-12 or JAN-DEC * / , -
Day of week Yes 0-6 or SUN-SAT * / , - L #
Year No 1970–2099 * / , -
我們定義第 0 個字段為 Seconds,第 1 個字段為 Minutes,各個字段的含義如下:
-
*星號表示cron表達式與該字段的所有值匹配。例如,在第四個字段(月)中使用星號表示每個月; -
/斜線描述在該時間段的間隔。例如,分鐘字段中的3-59/15表示每小時的第三分鐘,此后每15分鐘。*/...的形式相當于first-last/...的形式,即在該字段的最大可能范圍內的增量; -
,逗號用于分隔列表中的項目。例如,在第 5 個字段(星期)中使用MON,WED,FRI表示星期一、星期三和星期五; -
-連字符定義范圍。例如,2000-2010表示公元 2000 年至 2010 年之間的每一年,包括在內,為閉區間; -
L代表 “最后”。當在周天字段中使用時,它允許你指定諸如 “最后一個星期五”(5L)這樣的結構。在月日字段中,它指定了該月的最后一天; -
W月日字段允許使用W字符。這個字符用于指定離給定日期最近的工作日(周一至周五)。舉個例子,如果你指定15W作為月日字段的值,其含義是:“離本月 15 日最近的工作日”。所以,如果 15 號是星期六,觸發器在 14 號星期五啟動。如果 15 號是星期天,觸發器在 16 號星期一啟動。如果 15 號是星期二,那么它就在 15 號星期二觸發。但是,如果你指定1W作為月日的值,并且 1 號是星期六,那么觸發器在 3 號星期一發射,因為它不會 "跳過 "一個月的天數邊界。只有當月日是一個單一的日子,而不是一個范圍或日期列表時,才能指定
W字符。W字符也可以與L結合使用,如LW表示 “本月的最后一個工作日”。 -
#允許在星期字段中使用#,后面必須有一個 1 到 5 之間的數字。它允許你指定一些結構,如某個月的 “第二個星期五”。
2. 示例說明
Entry Description Equivalent to
@annually Run once a year at midnight in the morning of January 1 0 0 0 1 1 * *
@yearly Run once a year at midnight in the morning of January 1 0 0 0 1 1 * *
@monthly Run once a month at midnight in the morning of the first of the month 0 0 0 1 * * *
@weekly Run once a week at midnight in the morning of Sunday 0 0 0 * * 0 *
@daily Run once a day at midnight 0 0 0 * * * *
@hourly Run once an hour at the beginning of the hour 0 0 * * * * *
@reboot Not supported
3. 細節說明
- 如果只有六個字段,則會預加一個 0 秒字段,即
* * * * * 2013在內部成為0 * * * * 2013; - 如果只有五個字段,則預設 0 秒字段,并附加一個通配符年份字段,即
* * * * Mon內部成為0 * * * Mon *; - 星期字段的域是
[0-7],而不是[0-6],7 是星期天(像0)。這是為了符合http://linux.die.net/man/5/crontab#; - 如果提供了一個錯誤的cron表達式,代碼的行為是不確定的;
4. 安裝方式
go get github.com/gorhill/cronexpr
5. 重要函數
5.1 cronexpr.Parse
expr, err := cronexpr.Parse("*/5 * * * * * * ") // 如果表達式解析錯誤將返回一個錯誤
5.2 cronexpr.MustParse
expr = cronexpr.MustParse("*/5 * * * * * * ") // 如果表達式解析錯誤將直接拋出 panic
6. 代碼實現
6.1 簡單示例
package mainimport ("fmt""time""github.com/gorhill/cronexpr"
)func doTask() {fmt.Println("I am running, time is: ", time.Now())
}
func main() {// 每隔 5 秒執行1次expr, err := cronexpr.Parse("*/5 * * * * * * ") // 如果表達式解析錯誤將返回一個錯誤if err != nil {fmt.Println(err)return}nextTime := expr.Next(time.Now())fmt.Println(nextTime)time.AfterFunc(time.Until(nextTime), doTask)time.Sleep(10 * time.Second)}
6.2 監控任務和執行任務處于不同的協程
package mainimport ("fmt""time""github.com/gorhill/cronexpr"
)// 代表一個任務
type CronJob struct {expr *cronexpr.ExpressionnextTime time.Time // expr.Next(now)
}func main() {// 定時任務字典, key: 任務的名字, value 任務對象scheduleTable := make(map[string]*CronJob)now := time.Now()// 定義定時任務以每 5s 執行一次// MustParse 如果遇到解析 contab 錯誤時會直接拋出 panic ,不會像 Parse 一樣返回一個錯誤expr := cronexpr.MustParse("*/5 * * * * * *")cronJob := &CronJob{expr: expr,nextTime: expr.Next(now),}// 任務注冊到調度表scheduleTable["job1"] = cronJob// 定義定時任務以每 3s 執行一次expr = cronexpr.MustParse("*/3 * * * * * *")cronJob = &CronJob{expr: expr,nextTime: expr.Next(now),}// 任務注冊到調度表scheduleTable["job2"] = cronJob// 定時檢查一下任務調度表for {now := time.Now()for jobName, cronJob := range scheduleTable {// 判斷是否到期,當前時間等于定時任務的下次執行時間,或者當前時間大于任務的定時時間if now.Equal(cronJob.nextTime) || now.After(cronJob.nextTime) {// 啟動一個協程, 執行這個任務go func(jobName string) {fmt.Println("執行:", jobName)}(jobName)// 計算下一次調度時間cronJob.nextTime = cronJob.expr.Next(now)fmt.Println(jobName, "下次執行時間:", cronJob.nextTime)}}// 等待 1s,減少 CPU 消耗t := <-time.NewTimer(1 * time.Second).Cfmt.Println(t)}}
總結
以上是生活随笔為你收集整理的Go 学习笔记(77)— Go 第三方库之 cronexpr(解析 crontab 表达式,定时任务)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2022-2028年中国农用塑料薄膜行业
- 下一篇: 2022-2028年中国橡胶漆产业发展动