go之cron使用

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/fd3dda663953http://www.luyixian.cn/news_show_232522.aspx

 

posted @ 2020-04-21 22:00  ybf&yyj  阅读(2722)  评论(0编辑  收藏  举报