zoukankan      html  css  js  c++  java
  • go 定时任务库 cron

    简介

    在Linux中,Cron是计划任务管理系统,通过crontab命令使任务在约定的时间执行已经计划好的工作,例如定时备份系统数据、周期性清理缓存、定时重启服务等。

    本文介绍的cron库是一个用于管理定时任务的库,就是用Go实现Linux中crontab命令的相似效果。

    快速使用

    文本代码使用 Go Modules

    创建目录并初始化:

    $ mkdir cron && cd cron
    $ go mod init cron
    

    安装cron,目前最新稳定版本为 v3:

    $ go get -u github.com/robfig/cron/v3
    

    在项目中导入包使用:

    package main
    
    import (
      "fmt"
      "time"
    
      "github.com/robfig/cron/v3"
    )
    
    func main() {
      c := cron.New()
    
      c.AddFunc("@every 1s", func() {
        fmt.Println("tick every 1 second")
      })
    
      c.Start()
      
      // 阻塞,或者使用其他延迟时间函数、
      select{}
    }
    

    使用非常简单,创建cron对象,这个对象用于管理定时任务。

    调用cron对象的AddFunc()方法向管理器中添加定时任务。AddFunc()接受两个参数,参数 1 以字符串形式指定触发时间规则,参数 2 是一个无参的函数,每次触发时调用。@every 1s表示每秒触发一次,@every后加一个时间间隔,表示每隔多长时间触发一次。例如@every 1h表示每小时触发一次,@every 1m2s表示每隔 1 分 2 秒触发一次。time.ParseDuration()支持的格式都可以用在这里。

    调用c.Start()启动定时循环。

    注意一点,因为c.Start()启动一个新的 goroutine 做循环检测,我们在代码最后加了一行time.Sleep(time.Second * 5)防止主 goroutine 退出。

    运行效果,每隔 1s 输出一行字符串:

    $ go run main.go
    tick every 1 second
    tick every 1 second
    tick every 1 second
    tick every 1 second
    tick every 1 second
    

    时间格式

    与Linux 中crontab命令相似,cron库支持用 5 个空格分隔的域来表示时间。

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

    注意,月份和周历名称都是不区分大小写的,也就是说SUN/Sun/sun表示同样的含义(都是周日)。

    特殊字符含义如下:

    • 星号():使用的域可以匹配任何值,例如将月份域(第 5 个)设置为*,表示每个月;
    • 斜线(/):用来指定范围的步长,例如如第1个字段(minutes) 值是 3-59/15,表示每小时的第3分钟开始执行一次,之后每隔 15 分钟执行一次(即 3、18、33、48 这些时间点执行),这里也可以表示为:3/15;
    • 逗号(,):用来列举一些离散的值和多个范围,例如将周历的域(第 6 个)设置为MON,WED,FRI表示周一、三和五;
    • 连字号(-):用来表示范围,例如将小时的域(第 3 个)设置为9-17表示上午 9 点到下午 17 点(包括 9 和 17);
    • 问号(?):只能用在月历和周历的域中,用来代替*,表示每月/周的任意一天。
    • (L,W,#): Go中没有L,W,#的用法

    了解规则之后,我们可以定义任意时间:

    每隔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 * * ?
    

    记熟了这几个域的顺序,再多练习几次很容易就能掌握格式。熟悉规则了之后,就能熟练使用crontab命令了。

    func main() {
      c := cron.New()
    
      c.AddFunc("30 * * * *", func() {
        fmt.Println("Every hour on the half hour")
      })
    
      c.AddFunc("30 3-6,20-23 * * *", func() {
        fmt.Println("On the half hour of 3-6am, 8-11pm")
      })
    
      c.AddFunc("0 0 1 1 *", func() {
        fmt.Println("Jun 1 every year")
      })
    
      c.Start()
    
      for {
        time.Sleep(time.Second)
      }
    }
    

    预定义时间规则

    为了方便使用,cron预定义了一些时间规则:

    • @yearly:也可以写作@annually,表示每年第一天的 0 点。等价于0 0 1 1 *;
    • @monthly:表示每月第一天的 0 点。等价于0 0 1 * *;
    • @weekly:表示每周第一天的 0 点,注意第一天为周日,即周六结束,周日开始的那个 0 点。等价于0 0 * * 0;
    • @daily:也可以写作@midnight,表示每天 0 点。等价于0 0 * * *;
    • @hourly:表示每小时的开始。等价于0 * * * *。

    例如:

    func main() {
      c := cron.New()
    
      c.AddFunc("@hourly", func() {
        fmt.Println("Every hour")
      })
    
      c.AddFunc("@daily", func() {
        fmt.Println("Every day on midnight")
      })
    
      c.AddFunc("@weekly", func() {
        fmt.Println("Every week")
      })
    
      c.Start()
    
      for {
        time.Sleep(time.Second)
      }
    }
    

    上面代码只是演示用法,实际运行可能要等待非常长的时间才能有输出。

    注意:这样使用一个 cron.New() 的定时任务,执行的每个方法是顺序执行的,也就是说并不是同一时刻开始执行

    固定时间间隔

    cron支持固定时间间隔,格式为:

    @every <duration>
    

    含义为每隔duration触发一次。<duration>会调用time.ParseDuration()函数解析,所以ParseDuration支持的格式都可以。例如1h30m10s

    时区

    默认情况下,所有时间都是基于当前时区的。当然我们也可以指定时区,有 2 两种方式:

    • 在时间字符串前面添加一个CRON_TZ= + 具体时区,具体时区的格式在之前carbon的文章中有详细介绍。东京时区为Asia/Tokyo,纽约时区为America/New_York
    • 创建cron对象时增加一个时区选项cron.WithLocation(location)locationtime.LoadLocation(zone)加载的时区对象,zone为具体的时区格式。或者调用已创建好的cron对象的SetLocation()方法设置时区。

    示例:

    func main() {
      nyc, _ := time.LoadLocation("America/New_York")
      c := cron.New(cron.WithLocation(nyc))
      c.AddFunc("0 6 * * ?", func() {
        fmt.Println("Every 6 o'clock at New York")
      })
    
      c.AddFunc("CRON_TZ=Asia/Tokyo 0 6 * * ?", func() {
        fmt.Println("Every 6 o'clock at Tokyo")
      })
    
      c.Start()
    
      for {
        time.Sleep(time.Second)
      }
    }
    

    巨人的肩膀

    Go 每日一库之 cron
    Go 每日一库之定时任务库:cron
    Go -- cron定时任务的用法

  • 相关阅读:
    flask 模板block super()的讲解
    flask-include标签使用标签
    spring boot 使用属性加载顺序
    mongodb中的_id的ObjectId的生成规则
    由整数对(父节点和子节点的关系)组成的二叉树的高度问题
    Akka in action (第一章 介绍Akka)
    数据结构学习(一)数组
    spray-json
    JMS API(二)
    JSM 学习(一)
  • 原文地址:https://www.cnblogs.com/niuben/p/14615806.html
Copyright © 2011-2022 走看看