Golang 定时任务实现方法

线上服务一些不是很敏感的资源我们希望通过开启定时任务进行回收,Linux 下有 crontab 命令用于设置周期性被执行的指令,setitimer 也是 Linux 的 API,可以用于定时执行某个任务。下面介绍一个 Golang 实现的定时任务方法。

Cron 的定时任务表达式

   # ┌───────────── second (0 - 59)
   # │ ┌───────────── 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, or use names; 7 is also Sunday)
   # │ │ │ │ │ │
   # │ │ │ │ │ │
   # * * * * * * command to execute

 

字段名 是否必须 允许的值 允许的特定字符
秒(Seconds) 0-59 * / , –
分(Minutes) 0-59 * / , –
时(Hours) 0-23 * / , –
日(Day of month) 1-31 * / , – ?
月(Month) 1-12 or JAN-DEC * / , –
星期(Day of week) 0-6 or SUM-SAT * / , – ?

 

星号 * 表示该字段匹配所有的值,如果在最后一个参数星期里写 * ,则表示每一天。

斜线 / 表示时间间隔,如果在第二个参数分里写 1-59/10,表示从第 1 分钟开始,每隔 15 分钟执行一次(1、16、31、46时间点执行)。

逗号 , 表示枚举变量,如第五个参数写 Jan, Sep, Dec,则表示在一月、九月、十二月执行。

连字符 - 表示范围,如第一个参数秒写 1-10 表示从第一秒执行到第 10 秒。

问号 ? 只可用于日 ( Day of month ) 和 ( Day of week),表示不指定任何值,形同 *

 

时间表达式例子

每隔 5 秒执行一次:*/5 * * * * ?
每隔 1 分钟执行一次:0 */1 * * * ?
每天 23 点执行一次:0 0 23 * * ?
每天凌晨 1 点执行一次:0 0 1 * * ?
每月 1 号凌晨 1 点执行一次:0 0 1 1 * ?
在 26 分、29 分、33 分执行一次:0 26,29,33 * * * ?
每天的 0 点、13 点、18 点、21 点都执行一次:0 0 0,13,18,21 * * ?

主要接口

  • Cron:包含一系列要执行的实体

  type Cron struct {
      entries  []*Entry
      stop     chan struct{}   // 控制 Cron 实例暂停
      add      chan *Entry     // 当 Cron 已经运行了,增加新的任务通过 add 加入 channel 实现的
      snapshot chan []*Entry   // 获取当前所有 entity 的快照
      running  bool            // 当已经运行时为true;否则为false
  }
  • Entry:调度实体
  type Entry struct {

      // The schedule on which this job should be run.
      // 负责调度当前 Entity 中的 Job 执行
      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 下一次执行的时间
      Next time.Time

      // The last time this job was run. This is the zero time if the job has never
      // been run.
      // 上一次执行时间
      Prev time.Time

      // The Job to run.
      // 要执行的 Job
      Job Job
  }
  • Job:每个实体包含一个需要运行的任务
  • 希望定期运行的任务,就需要实现 job 接口
 type Job interface {
      Run()
  }
Schedule:每个实体包含一个调度器,调度 job 的执行
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 下一次执行的时间

  Next(time.Time) time.Time

}

使用方法

  • 实例化 Cron
  func New() *Cron {

      return &Cron{
          entries:  nil,
          add:      make(chan *Entry),
          stop:     make(chan struct{}),
          snapshot: make(chan []*Entry),
          running:  false,

      }
  }
  • 实例化时间表达式
    每天凌晨三点执行 0 0 3 * * ?
func (c *Cron) AddFunc(spec string, cmd func()) error
配置定时任务的钩子函数
//cronTask execute task periodically
func NewCronTask() *cron.Cron {
    logrus.Info("cron task begin....")
    c := cron.New()
    specForVlan := "0 0 3 * * ?"
    c.AddFunc(specForVlan, func() {
        vlanCleaner()
    })
 
    specForDsa := "0 0 4 * * ?"
    c.AddFunc(specForDsa, func() {
        dsaCleanerCronTask()
    })
 
    c.Start()
    return c
}
 
func dsaCleanerCronTask(){
    //定时清除 dsa  资源的函数 body
}
 
func vlanCleaner(){
    //定时清除 vlan 资源的函数 body
}

发表评论