Go 每日一库之定时任务库:cron
liuian 2024-12-01 00:59 76 浏览
以下文章来源于Golang技术分享 ,作者机器铃砍菜刀
在Linux中,Cron是计划任务管理系统,通过crontab命令使任务在约定的时间执行已经计划好的工作,例如定时备份系统数据、周期性清理缓存、定时重启服务等。本文介绍的cron库,就是用Go实现Linux中crontab命令的相似效果。
使用示例
安装下载cron,目前最新的稳定版已经迭代到了v3
go get github.com/robfig/cron/v3@v3.0.0
在项目中导入包
import "github.com/robfig/cron/v3"
使用
1package main
2
3import (
4 "fmt"
5
6 "github.com/robfig/cron/v3"
7)
8
9func main() {
10 c := cron.New()
11 c.AddFunc("30 * * * *", func() { fmt.Println("Every hour on the half hour") })
12 c.AddFunc("30 3-6,20-23 * * *", func() { fmt.Println(".. in the range 3-6am, 8-11pm") })
13 c.AddFunc("CRON_TZ=Asia/Tokyo 30 04 * * *", func() { fmt.Println("Runs at 04:30 Tokyo time every day") })
14 c.AddFunc("@hourly", func() { fmt.Println("Every hour, starting an hour from now") })
15 c.AddFunc("@every 1h30m", func() { fmt.Println("Every hour thirty, starting an hour thirty from now") })
16 c.AddFunc("@every 1s", func() {fmt.Println("Every 1 second, starting an hour thirty from now")})
17 c.Start()
18 select {}
19}
创建cron对象
使用时,首先通过cron.New()创建cron对象,通过该对象管理定时任务。通过调用cron的AddFunc()方法添加定时任务。AddFun()入参为二,参数一是以字符串的形式指定触发任务规则,参数二是无入参的函数,任务触发时执行函数。
- 添加触发任务
30 * * * *表示每个小时内的第30分钟时触发;30 3-6,20-23 * * *表示在早上3点到6点,下午8点到11点的第30分钟时触发;CRON_TZ=Asia/Tokyo 30 04 * * *表示东京时间每天早上4点半触发;@hourly表示从添加该任务时算起的之后每小时触发;@every 1h30m表示从添加该任务时算起的之后每一个半小时触发;@every 1s表示从添加该任务时算起的之后每秒触发。
- 启动定时循环
通过调用cron.Start()启动定时循环任务。
输出
1 nbsp;go run main.go
2Every 1 second, starting an hour thirty from now
3Every 1 second, starting an hour thirty from now
4Every 1 second, starting an hour thirty from now
5Every 1 second, starting an hour thirty from now
6...
由于只让以上程序运行了几秒的时间,因此,输出中只包含执行了每秒触发的打印。随着程序运行时间的加长,其他触发任务也会在满足条件时进行打印。
cron时间表达式规则
cron表达式默认通过使用5个以空格分隔的字段组合来表示触发时间(和linux的crontab保持一致)。
1cron.New(
2 cron.WithParser(
3 cron.NewParser(
4 cron.Second | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor)))
如同30 * * * *一样,默认第1个字段表示分钟,第2个字段表示小时,第3个字段表示每月中的日期,第4个字段表示月份数,第5个字段表示星期几。
cron还提供了强大的自定义时间格式功能,可以通过调用cron.NewParser()创建自定义Parser对象,例如通过以下方式定义新的cron时间表达式规则
1cron.New(cron.WithSeconds())
这样,时间字段一共是7位,第1位就是指定秒。秒执行的时间表达式就可以用1 * * * * * *表示。
因为添加Seconds是对标准cron规范的最常见修改,因此cron提供了一个内置函数cron.WithSeconds()来执行此操作,该函数等效于之前使用的自定义解析器。
1cron.New(cron.WithSeconds())
- 预定义时间表
由于cron的时间表达式可读性不是很好,因此cron库预定义了一些字符串来表示特定的时间规则。
1Entry | Description | Equivalent To
2----- | ----------- | -------------
3@yearly (or @annually) | Run once a year, midnight, Jan. 1st | 0 0 1 1 *
4@monthly | Run once a month, midnight, first of month | 0 0 1 * *
5@weekly | Run once a week, midnight between Sat/Sun | 0 0 * * 0
6@daily (or @midnight) | Run once a day, midnight | 0 0 * * *
7@hourly | Run once an hour, beginning of hour | 0 * * * *
- 时间间隔
cron还提供了更具可读性的固定时间间隔格式
1@every <duration>
它代码每隔duration触发执行一次任务。这里的duration是通过调用标准库time的ParseDuration()函数解析的,所以只要ParseDuration()支持的格式都能支持。例如上文示例的@every 1h30m和@every 1s。
cron可控选项
在cron源码option.go文件中,暴露了5个函数供开发者控制cron对象的选项。
- WithLocation()
指定时区。默认情况下基于当前时区(在Unix系统中,查询TZ环境变量确定要使用的时区,若未定义TZ,则使用/etc/localtime文件中的定义时区)。可通过在时间字符串前添加CRON_TZ=字符串再加上具体的时区。例如东京时区为Asia/Tokyo。
1c.AddFunc("CRON_TZ=Asia/Tokyo 30 04 * * *", func() { fmt.Println("Runs at 04:30 Tokyo time every day") })
- WithParser()
自定义时间解析器,上文已有示例,这里不再赘述。
- WithSeconds()
增加对秒的时间格式支持,其内部调用的WithParser()方法。
1func WithSeconds() Option {
2 return WithParser(NewParser(
3 Second | Minute | Hour | Dom | Month | Dow | Descriptor,
4 ))
5}
- WithChain()
Job包装器,下文中会讲解Job接口。
- WithLogger()
Logger是cron中用于记录日志的接口,WithLogger()可以设置自定义的Logger。
1package main
2
3import (
4 "fmt"
5 "log"
6 "os"
7
8 "github.com/robfig/cron/v3"
9)
10
11func main() {
12 c := cron.New(cron.WithLogger(cron.VerbosePrintfLogger(log.New(os.Stdout, "cron process: ", log.LstdFlags))))
13 c.AddFunc("@every 1s", func() { fmt.Println("Every 1 second") })
14 c.Start()
15 select {}
16}
该logger记录了cron内部的调度过程,输入如下
1go run main.go
2cron process: 2020/08/30 00:07:04 start
3cron process: 2020/08/30 00:07:04 schedule, now=2020-08-30T00:07:04+08:00, entry=1, next=2020-08-30T00:07:05+08:00
4cron process: 2020/08/30 00:07:05 wake, now=2020-08-30T00:07:05+08:00
5cron process: 2020/08/30 00:07:05 run, now=2020-08-30T00:07:05+08:00, entry=1, next=2020-08-30T00:07:06+08:00
6Every 1 second
7cron process: 2020/08/30 00:07:06 wake, now=2020-08-30T00:07:06+08:00
8Every 1 second
9cron process: 2020/08/30 00:07:06 run, now=2020-08-30T00:07:06+08:00, entry=1, next=2020-08-30T00:07:07+08:00
10cron process: 2020/08/30 00:07:07 wake, now=2020-08-30T00:07:07+08:00
11cron process: 2020/08/30 00:07:07 run, now=2020-08-30T00:07:07+08:00, entry=1, next=2020-08-30T00:07:08+08:00
12Every 1 second
13...
自定义Job
cron中定义了Job接口,对象只要实现了Job接口所定义的Run()方法,均可以调用cron.AddJob()方法将该对象添加到定时管理器中。
1// Job is an interface for submitted cron jobs.
2type Job interface {
3 Run()
4}
AddFunc()
在上文示例中,通过cron.AddFunc()方法为cron对象添加定时任务。实质上,AddFunc()方法内部调用的也是AddJob()方法:定义新类型对象FuncJob,为其实现Job接口,在AddFunc()方法中,将回调参数func()转为FuncJob类型,调用AddJob()方法。
1type FuncJob func()
2
3func (f FuncJob) Run() { f() }
4
5func (c *Cron) AddFunc(spec string, cmd func()) (EntryID, error) {
6 return c.AddJob(spec, FuncJob(cmd))
7}
- 自实现Job接口
除了通过AddFunc()将无参函数直接作为回调外,我们还可以通过AddJon()自定义对象。
如下,自定义对象CallJob,实现Run()方法。
1package main
2
3import (
4 "fmt"
5 "time"
6
7 "github.com/robfig/cron/v3"
8)
9
10type CallJob struct {
11 name string
12 number int
13}
14
15func (c CallJob) Run() {
16 fmt.Printf("call %s : %d\n", c.name, c.number)
17}
18func main() {
19 c := cron.New()
20 c.AddJob("@every 1s", CallJob{
21 name: "Bob",
22 number: 13888888888,
23 })
24 c.Start()
25
26 time.Sleep(3 * time.Second)
27}
输出
1 nbsp;go run main.go
2call Bob : 13888888888
3call Bob : 13888888888
4call Bob : 13888888888
总结
cron库为go开发者提供了强大的定时任务管理功能,它的时间表达式格式和linux下的crontab命令是对齐的。
cron的代码并不算多,其核心定时管理功能依赖了go标准库time和sort,非常值得学习和参考。另外有一个基于该库抽离出来的最小化定时任务库gron,更易理解和使用,文末会附上该库地址。
cron是小菜刀在实际项目中引入过的三方库,感觉挺不错,就总结出来分享给大家。如果你喜欢看更多关于三方库的文章,请点赞支持。
仓库地址
1. https://github.com/robfig/cron
2. https://github.com/roylee0704/gron
相关推荐
-
- 驱动网卡(怎么从新驱动网卡)
-
网卡一般是指为电脑主机提供有线无线网络功能的适配器。而网卡驱动指的就是电脑连接识别这些网卡型号的桥梁。网卡只有打上了网卡驱动才能正常使用。并不是说所有的网卡一插到电脑上面就能进行数据传输了,他都需要里面芯片组的驱动文件才能支持他进行数据传输...
-
2026-01-30 00:37 liuian
- win10更新助手装系统(微软win10更新助手)
-
1、点击首页“系统升级”的按钮,给出弹框,告诉用户需要上传IMEI码才能使用升级服务。同时给出同意和取消按钮。华为手机助手2、点击同意,则进入到“系统升级”功能华为手机助手华为手机助手3、在检测界面,...
- windows11专业版密钥最新(windows11专业版激活码永久)
-
Windows11专业版的正版密钥,我们是对windows的激活所必备的工具。该密钥我们可以通过微软商城或者通过计算机的硬件供应商去购买获得。获得了windows11专业版的正版密钥后,我...
-
- 手机删过的软件恢复(手机删除过的软件怎么恢复)
-
操作步骤:1、首先,我们需要先打开手机。然后在许多图标中找到带有[文件管理]文本的图标,然后单击“文件管理”进入页面。2、进入页面后,我们将在顶部看到一行文本:手机,最新信息,文档,视频,图片,音乐,收藏,最后是我们正在寻找的[更多],单击...
-
2026-01-29 23:55 liuian
- 一键ghost手动备份系统步骤(一键ghost 备份)
-
步骤1、首先把装有一键GHOST装系统的U盘插在电脑上,然后打开电脑马上按F2或DEL键入BIOS界面,然后就选择BOOT打USDHDD模式选择好,然后按F10键保存,电脑就会马上重启。 步骤...
- 怎么创建局域网(怎么创建局域网打游戏)
-
1、购买路由器一台。进入路由器把dhcp功能打开 2、购买一台交换机。从路由器lan端口拉出一条网线查到交换机的任意一个端口上。 3、两台以上电脑。从交换机任意端口拉出网线插到电脑上(电脑设置...
- 精灵驱动器官方下载(精灵驱动手机版下载)
-
是的。驱动精灵是一款集驱动管理和硬件检测于一体的、专业级的驱动管理和维护工具。驱动精灵为用户提供驱动备份、恢复、安装、删除、在线更新等实用功能。1、全新驱动精灵2012引擎,大幅提升硬件和驱动辨识能力...
- 一键还原系统步骤(一键还原系统有哪些)
-
1、首先需要下载安装一下Windows一键还原程序,在安装程序窗口中,点击“下一步”,弹出“用户许可协议”窗口,选择“我同意该许可协议的条款”,并点击“下一步”。 2、在弹出的“准备安装”窗口中,可...
- 电脑加速器哪个好(电脑加速器哪款好)
-
我认为pp加速器最好用,飞速土豆太懒,急速酷六根本不工作。pp加速器什么网页都加速,太任劳任怨了!以上是个人观点,具体性能请自己试。ps:我家电脑性能很好。迅游加速盒子是可以加速电脑的。因为有过之...
- 任何u盘都可以做启动盘吗(u盘必须做成启动盘才能装系统吗)
-
是的,需要注意,U盘的大小要在4G以上,最好是8G以上,因为启动盘里面需要装系统,内存小的话,不能用来安装系统。内存卡或者U盘或者移动硬盘都可以用来做启动盘安装系统。普通的U盘就可以,不过最好U盘...
- u盘怎么恢复文件(u盘文件恢复的方法)
-
开360安全卫士,点击上面的“功能大全”。点击文件恢复然后点击“数据”下的“文件恢复”功能。选择驱动接着选择需要恢复的驱动,选择接入的U盘。点击开始扫描选好就点击中间的“开始扫描”,开始扫描U盘数据。...
- 系统虚拟内存太低怎么办(系统虚拟内存占用过高什么原因)
-
1.检查系统虚拟内存使用情况,如果发现有大量的空闲内存,可以尝试释放一些不必要的进程,以释放内存空间。2.如果系统虚拟内存使用率较高,可以尝试增加系统虚拟内存的大小,以便更多的应用程序可以使用更多...
-
- 剪贴板权限设置方法(剪贴板访问权限)
-
1、首先打开iphone手机,触碰并按住单词或图像直到显示选择选项。2、其次,然后选取“拷贝”或“剪贴板”。3、勾选需要的“权限”,最后选择开启,即可完成苹果剪贴板权限设置。仅参考1.打开苹果手机设置按钮,点击【通用】。2.点击【键盘】,再...
-
2026-01-29 21:37 liuian
- 平板系统重装大师(平板重装win系统)
-
如果你的平板开不了机,但可以连接上电脑,那就能好办,楼主下载安装个平板刷机王到你的个人电脑上,然后连接你的平板,平板刷机王会自动识别你的平板,平板刷机王上有你平板的我刷机包,楼主点击下载一个,下载完成...
- 联想官网售后服务网点(联想官网售后服务热线)
-
联想3c服务中心是联想旗下的官方售后,是基于互联网O2O模式开发的全新服务平台。可以为终端用户提供多品牌手机、电脑以及其他3C类产品的维修、保养和保险服务。根据客户需求层次,联想服务针对个人及家庭客户...
- 一周热门
- 最近发表
- 标签列表
-
- python判断字典是否为空 (50)
- crontab每周一执行 (48)
- aes和des区别 (43)
- bash脚本和shell脚本的区别 (35)
- canvas库 (33)
- dataframe筛选满足条件的行 (35)
- gitlab日志 (33)
- lua xpcall (36)
- blob转json (33)
- python判断是否在列表中 (34)
- python html转pdf (36)
- 安装指定版本npm (37)
- idea搜索jar包内容 (33)
- css鼠标悬停出现隐藏的文字 (34)
- linux nacos启动命令 (33)
- gitlab 日志 (36)
- adb pull (37)
- python判断元素在不在列表里 (34)
- python 字典删除元素 (34)
- vscode切换git分支 (35)
- python bytes转16进制 (35)
- grep前后几行 (34)
- hashmap转list (35)
- c++ 字符串查找 (35)
- mysql刷新权限 (34)
