Go 定时任务

文主要介绍 Go 定时任务包:https://github.com/robfig/cron 的使用。

快速上手

下载包,截至本文发布,版本为:v3.0.1

1
go get github.com/robfig/cron/v3@v3.0.1

简单示例: 每三秒打印字符串blog.mango.im,后面死循环保证主 Goroutine 不退出

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package main

import (
	"github.com/robfig/cron/v3"
	"log"
	"time"
)

func main()  {
	log.Println("starting...")

	c := cron.New()

	c.AddFunc("@every 3s", func() {
		log.Println("print blog.mango.im per 3s ")
	})

	c.Start()

	for {
		time.Sleep(10 * time.Hour)
		log.Println("main goroutine")
	}
}

用法

调用者可以注册要按给定计划表调用的方法。 Cron 将在它们自己的 goroutine 中运行它们。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
c := cron.New()
c.AddFunc("0 30 * * * *", func() { fmt.Println("每半小时") })
c.AddFunc("@hourly",      func() { fmt.Println("每小时") })
c.AddFunc("@every 1h30m", func() { fmt.Println("每小时三十分") })
c.Start()
..
// 方法异步调用自己的 goroutine
...
// 方法也可以添加到正在运行的 Cron
c.AddFunc("@daily", func() { fmt.Println("每天") })
..
// 检查 cron 作业条目的下一次和上一次运行时间。
inspect(c.Entries())
..
c.Stop()  // 停止调度程序(不停止任何已经运行的作业)。

CRON 表达式格式

cron 表达式表示一组时间,使用6个空格分隔的字段。

字段名        | 是否强制?    | 允许的值          | 允许的特殊字符 
----------   | ---------- | --------------  | --------------------------
Seconds      | Yes        | 0-59            | * / , -
Minutes      | Yes        | 0-59            | * / , -
Hours        | Yes        | 0-23            | * / , -
Day of month | Yes        | 1-31            | * / , - ?
Month        | Yes        | 1-12 or JAN-DEC | * / , -
Day of week  | Yes        | 0-6 or SUN-SAT  | * / , - ?

注意:月份和星期几字段值不区分大小写。 “SUN”、“Sun”和“sun”同样被接受。

特殊字符

星号 ( * )

星号表示 cron 表达式将匹配字段的所有值;例如,在第 5 个字段(月)中使用星号表示每个月。

斜线 ( / )

斜线用于描述范围的增量。例如,第 1 个字段(分钟)中的 3-59/15 将表示一小时的第 3 分钟,此后每 15 分钟一次。形式“*/…”等价于形式“first-last/…”,即在字段的最大可能范围内递增。接受形式“N/…”表示“N-MAX/…”,即从 N 开始,使用增量直到该特定范围结束。它不会环绕。

逗号 ( , )

逗号用于分隔列表中的项目。例如,在第 5 个字段(星期几)中使用“MON,WED,FRI”表示星期一、星期三和星期五。

连字符 ( - )

连字符用于定义范围。例如,9-17 表示上午 9 点到下午 5 点之间的每小时。

问号(?)

可以使用问号代替“*”以将月中的某天或一周中的某天留空。

预定义计划

你可以使用多个预定义计划之一来代替 cron 表达式。

条目                    | 描述                              | 等同于
-----                  | -----------                      | -------------
@yearly (or @annually) | 每年运行一次,1月1号0点              | 0 0 0 1 1 *
@monthly               | 每月运行一次,每月第一天0点           | 0 0 0 1 * *
@weekly                | 每周运行一次,周日0点                | 0 0 0 * * 0
@daily (or @midnight)  | 每天运行一次,0点                   | 0 0 0 * * *
@hourly                | 每小时运行一次,                    | 0 0 * * * *

间隔

你还可以安排一个任务以固定的时间间隔执行,从它被添加或 cron 运行时开始。 这是通过像这样格式化 cron 规范来支持的:

1
@every <duration>

其中“duration”是 time.ParseDuration (http://golang.org/pkg/time/#ParseDuration) 接受的字符串。

例如,“@every 1h30m10s”表示在每 1 小时 30 分 10 秒后就开始运行任务。

注意:间隔不考虑任务运行时间。 例如,如果任务需要 3 分钟运行,并且计划每 5 分钟运行一次,则每次运行之间只有 2 分钟的空闲时间。

时区

所有的解释和调度都是在机器的本地时区完成的(由 Go 时间包(http://www.golang.org/pkg/time)提供)。

请注意,在夏令时跨越式过渡期间安排的作业将不会运行!

线程安全

由于 Cron 服务与调用代码同时运行,因此必须采取一定的措施以确保正确同步。

所有 cron 方法都被设计为正确同步,只要调用者确保调用在它们之间有明确的发生前排序。

执行

Cron 条目存储在一个数组中,按它们的下一个激活时间排序。 Cron 休眠直到下一个作业要运行。

醒来后:

  • 它运行在那一秒处于活动状态的每个条目
  • 它计算已运行作业的下一次运行时间
  • 它按下次激活时间重新排序条目数组。
  • 它进入睡眠状态,直到最快的工作。

参考:https://pkg.go.dev/github.com/robfig/cron

updatedupdated2021-06-222021-06-22
Load Comments?