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定时任务的用法

  • 相关阅读:
    Android 按键消息处理Android 按键消息处理
    objcopy
    SQLite多线程读写实践及常见问题总结
    android动画坐标定义
    Android动画效果translate、scale、alpha、rotate
    Android公共库(缓存 下拉ListView 下载管理Pro 静默安装 root运行 Java公共类)
    Flatten Binary Tree to Linked List
    Distinct Subsequences
    Populating Next Right Pointers in Each Node II
    Populating Next Right Pointers in Each Node
  • 原文地址:https://www.cnblogs.com/niuben/p/14615806.html
Copyright © 2011-2022 走看看