1、cron表达式的基本格式
在linux中使用过crontab,对定时任务应该就会有所了解,linux中利用crontab -e打开crontab表来添加定时任务,但是只能精确到分钟,go中却可以精确到秒。表达式如下:
┌─────────────second 范围 (0 - 60)
│ ┌───────────── min (0 - 59)
│ │ ┌────────────── hour (0 - 23)
│ │ │ ┌─────────────── day of month (1 - 31)
│ │ │ │ ┌──────────────── month (1 - 12)
│ │ │ │ │ ┌───────────────── day of week (0 - 6) (0 to 6 are Sunday to
│ │ │ │ │ │ Saturday)
│ │ │ │ │ │
│ │ │ │ │ │
* * * * * *
2、特殊字符
星号:匹配所有值
斜线:增长间隔,*/5表示5 10 15....分钟运行
逗号:枚举值,1,13,21表示1 13 21分钟运行
连字符:表示范围,10-15表示10 11 12 13 15分钟运行
问号:只用于日和星期,表示不指定,可用*替代
3、go中cron设计思路
//cron实体 type Cron struct { entries []*Entry stop chan struct{} //控制Cron实例暂停 add chan *Entry //当Cron已经运行了,增加新的Entity,是通过add该channel实现的 snapshot chan []*Entry //获取当前所有entity的快照 running bool //是否正在运行中 ...... } //调度实体 type Entry struct { //负责调度当前Entity中的Job执行 Schedule Schedule //Job下一步执行的时间 Next time.Time //Job上一次执行时间 Prev time.Time //要执行的Job Job Job } //每一个运行的试题包含一个Job type Job interface { Run() } //实现Job接口 type FuncJob func() //通过简单的run()来实现job func (f FuncJob) Run() { f() } //每个实体包含一个调度器 type Schedule interface { //返回同一Entity中的job下一次执行的时间 Next(time.Time) time.Time } type SpecSchedule struct { Second, Minute, Hour, Dom, Month, Dow uint64 } type ConstantDelaySchedule struct { Delay time.Duration //循环时间间隔,最小单位为秒 } //实例化Cron func New() *Cron { return &Cron{ entries: nil, add: make(chan *Entry), stop: make(chan struct{}), snapshot: make(chan []*Entry), running: false, } } func Parse(spec string) (_ Schedule, err error) //将job加入Cron中,该方法只是简单的通过FuncJob类型强制转换cmd,然后调用AddJob方法 func (c *Cron) AddFunc(spec string, cmd func()) error //将job加入Cron中,通过Parse函数解析cron表达式spec的到调度实例(Schedule),之后调用c.Schedule方法 func (c *Cron) AddJob(spec string, cmd Job) error //获取当前Cron总所有Entities的快照 func (c *Cron) Entries() []*Entry //通过两个参数实例化一个Entity,然后加入当前的Cron中,如果当前Cron未运行,则直接将该Entity加入Cron中 //否则通过add这个成员channel将entity加入正在运行的Cron中 func (c *Cron) Schedule(schedule Schedule, cmd Job) //新启动一个goroutine运行当前Cron func (c *Cron) Start() //通过给stop成员发送一个struct{}{}来停止当前的Cron,同时将running置为false, //从这里可以看出来stop只是去通知Cron停止,因此往channel发一个值即可,不用关心值的大小, //所以Cron中stop是一个空结构体 func (c *Cron) Stop()
4、示例:
package main import ( "log" "github.com/robfig/cron" ) //linux中crontab只能精确到分钟,go中支持秒级别的 func newWithSecond() *cron.Cron { secondParser := cron.NewParser(cron.Second | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.DowOptional | cron.Descriptor) return cron.New(cron.WithParser(secondParser), cron.WithChain()) } type H struct { C *cron.Cron } func (h H) Run() { entries := h.C.Entries() if len(entries) > 0 { log.Println("---------cron running entries:", len(entries), ", next time:", entries[1].Next, ", pre time:", entries[1].Prev) } } func main() { i := 0 c := newWithSecond() spec := "*/5 * * * * *" entryId, err := c.AddFunc(spec, func() { i++ log.Println("cron running:", i) if i >= 1 { entries := c.Entries() log.Println("cron running entries:", len(entries), ", next time:", entries[0].Next, ", pre time:", entries[0].Prev) } }) log.Println("entryId:", entryId, " err:", err) s, err := cron.ParseStandard("*/1 * * * * ") if err != nil { log.Println(err) } h := H{c} c.Schedule(s, h) c.Start() select {} }
参考地址:https://www.jianshu.com/p/fd3dda663953、http://www.luyixian.cn/news_show_232522.aspx