cron 计划任务 #
cron 是 https://github.com/robfig/cron 库的二次封装,便于进行可视化管理。
意义 #
robfig/cron 已经完成了计划任务的所有基础功能,在实际项目中,我们还有两个需要自己实现的需求。
配置化,不实现后台管理功能,大部分项目也会实现通过配置文件、或者在代码当中组装计划任务,来达到管理的目的。
后台可视化管理,大多数项目都有可视化后台,希望在后台可以自由的管理计划任务。
定义 #
每一个cron由 name spec entryId job 四个元素构成
name - 每一个cron的名称,例如后台显示、作为日志当中的tag,这个name是langgo框架定义的,必须是惟一的。
spec - robfig/cron 当中原始的属性,用来表示cron的策略。
entryId - entry 是 robfig/cron 把当前存在的cron称为entry,每一个entry会有一个id,通过id来删除已经存在的计划任务。
job - job 是计划任务实际的执行实例。
基本使用方法 在代码当中组装 #
import (
rcron "github.com/robfig/cron/v3"
"fmt"
)
type MyJob struct {
Name string
}
func (j MyJob) Run() {
fmt.Println(j.Name, time.Now())
}
func main() {
langgo.Run(&cron.Instance{WithSeconds: true})
wait := make(chan struct{})
cron.Get().BindTaskAndSchedule("basic", "* * * * * *", MyJob{Name: "basic"})
<-wait
}
MyJob 是 rcron.Job 的具体实例,通过 BindTaskAndSchedule() 方法,对具体的实例 MyJob 关联 name 和 spec 属性。其中 spec 属性是计划任务的执行策略。当WithSeconds=true,策略包含秒,WithSeconds=false,策略不包秒只能执行到分,所以当前的例子是每秒钟执行一次 MyJob.Run() 方法
WithSeconds #
查看 robfig/cron 源代码 当 WithSeconds = false
var standardParser = NewParser(
Minute | Hour | Dom | Month | Dow | Descriptor,
)
当 WithSeconds = true
func WithSeconds() Option {
return WithParser(NewParser(
Second | Minute | Hour | Dom | Month | Dow | Descriptor,
))
}
从配置中加载 #
定义配置文件cron.yml
- name: "my job 1"
spec: "* * * * * *"
- name: "my job 2"
spec: "*/5 * * * * *"
代码:
import (
rcron "github.com/robfig/cron/v3"
"gopkg.in/yaml.v3"
"fmt"
"os"
)
func main() {
langgo.Run(&cron.Instance{WithSeconds: true})
wait := make(chan struct{})
cron.Get().BindTask("my job 1", MyJob{Name: "my job 1"})
cron.Get().BindTask("my job 2", MyJob{Name: "my job 2"})
data, err := os.ReadFile("../../testdata/cron.yml")
if err != nil {
return
}
var schedules []Schedule
yaml.Unmarshal(data, &schedules)
cron.Get().Load(schedules...)
for _, entry := range cron.Get().cron.Entries() {
fmt.Println(entry)
}
<-wait
}
调用 BindTask() 方法给每一个 MyJob 实例绑定一个 name 属性。调用 Load() 方法给每一个 task 绑定一个 spec 属性,完成计划任务的初始化。当前这个例子 my job 1 每秒执行一次,my job 2 5秒执行一次
后台UI可视化管理 #
如果您希望从后台UI管理所有的计划任务,可以按照下面的方式实现。
...
cron.Get().BindTask("my job 1", MyJob{Name: "my job 1"})
cron.Get().BindTask("my job 2", MyJob{Name: "my job 2"})
for _, task := range cron.Get().Tasks() {
fmt.Println(task)
}
...
通过 BindTask 方法在代码中绑定出所有的Task。通过 Tasks() 方法拿到所有的name,封装一个系统API提供给后台UI,实现计划任务的选择列表。
...
entryId, _ := cron.Get().UpdateSchedule("my job 1", "* 1 * * * * *")
...
实现一个API,通过调用 UpdateSchedule() 方法刷新cron的spec属性。返回值是cron的 entryId,通过这个entryId可以删除已经存在的计划任务。
...
for _, entry := range cron.GetCron().Entries() {
fmt.Println("entry", entry)
}
...
输出:
entry {1 0x1400017f140 2022-11-17 14:44:13 +0800 CST 0001-01-01 00:00:00 +0000 UTC 0x102af6a10 {my job 1}}
entry {2 0x1400017f180 2022-11-17 14:44:15 +0800 CST 0001-01-01 00:00:00 +0000 UTC 0x102af6a10 {my job 2}}
通过 GetCron().Entries() 方法可以打印出当前生效的所有计划任务,可以编写一个API提供给后台UI展示所有当前计划任务。
...
entryId, _ := cron.Get().RemoveTask("my job 1")
...
通过 RemoveTask() 方法移除已经存在的cron。