Go Gin 系列十一:Cron定时任务
知识点
完成定时任务的功能
本文目标
在实际的应用项目中,定时任务的使用是很常见的。你是否有过 Golang 如何做定时任务的疑问,莫非是轮询,在本文中我们将结合我们的项目讲述 Cron。
介绍
我们将使用 cron 这个包,它实现了 cron 规范解析器和任务运行器,简单来讲就是包含了定时任务所需的功能
Cron 表达式格式
字段名 | 是否必填 | 允许的值 | 允许的特殊字符 |
---|---|---|---|
秒(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 | * / , - ? |
Cron 表达式表示一组时间,使用 6 个空格分隔的字段
可以留意到 Golang 的 Cron 比 Crontab 多了一个秒级,以后遇到秒级要求的时候就省事了
Cron 特殊字符
1、星号 ( * )
星号表示将匹配字段的所有值
2、斜线 ( / )
斜线用户 描述范围的增量,表现为 “N-MAX/x”,first-last/x 的形式,例如 3-59/15 表示此时的第三分钟和此后的每 15 分钟,到 59 分钟为止。即从 N 开始,使用增量直到该特定范围结束。它不会重复
3、逗号 ( , )
逗号用于分隔列表中的项目。例如,在 Day of week 使用“MON,WED,FRI”将意味着星期一,星期三和星期五
4、连字符 ( - )
连字符用于定义范围。例如,9 - 17 表示从上午 9 点到下午 5 点的每个小时
5、问号 ( ? )
不指定值,用于代替 “ * ”,类似 “ _ ” 的存在,不难理解
预定义的 Cron 时间表
输入 | 简述 | 相当于 |
---|---|---|
@yearly (or @annually) | 1 月 1 日午夜运行一次 | 0 0 0 1 1 * |
@monthly | 每个月的午夜,每个月的第一个月运行一次 | 0 0 0 1 * * |
@weekly | 每周一次,周日午夜运行一次 | 0 0 0 * * 0 |
@daily (or @midnight) | 每天午夜运行一次 | 0 0 0 * * * |
@hourly | 每小时运行一次 | 0 0 * * * * |
安装
$ go get -u github.com/robfig/cron
实践
在上一章节 Gin 实践 连载十 定制 GORM Callbacks 中,我们使用了 GORM 的回调实现了软删除,同时也引入了另外一个问题
就是我怎么硬删除,我什么时候硬删除?这个往往与业务场景有关系,大致为
另外有一套硬删除接口
定时任务清理(或转移、backup)无效数据
在这里我们选用第二种解决方案来进行实践
编写硬删除代码
打开 models 目录下的 tag.go、article.go 文件,分别添加以下代码
1、tag.go
func CleanAllTag() bool {db.Unscoped().Where("deleted_on != ? ", 0).Delete(&Tag{})return true
}
2、article.go
func CleanAllArticle() bool {db.Unscoped().Where("deleted_on != ? ", 0).Delete(&Article{})return true
}
注意硬删除要使用 Unscoped()
,这是 GORM 的约定
编写 Cron
在 项目根目录下新建 cron.go 文件,用于编写定时任务的代码,写入文件内容
package mainimport ("time""log""github.com/robfig/cron""github.com/EDDYCJY/go-gin-example/models"
)func main() {log.Println("Starting...")c := cron.New()c.AddFunc("* * * * * *", func() {log.Println("Run models.CleanAllTag...")models.CleanAllTag()})c.AddFunc("* * * * * *", func() {log.Println("Run models.CleanAllArticle...")models.CleanAllArticle()})c.Start()t1 := time.NewTimer(time.Second * 10)for {select {case <-t1.C:t1.Reset(time.Second * 10)}}
}
在这段程序中,我们做了如下的事情
cron.New()
会根据本地时间创建一个新(空白)的 Cron job runner
func New() *Cron {return NewWithLocation(time.Now().Location())
}// NewWithLocation returns a new Cron job runner.
func NewWithLocation(location *time.Location) *Cron {return &Cron{entries: nil,add: make(chan *Entry),stop: make(chan struct{}),snapshot: make(chan []*Entry),running: false,ErrorLog: nil,location: location,}
}
c.AddFunc()
AddFunc 会向 Cron job runner 添加一个 func ,以按给定的时间表运行
func (c *Cron) AddJob(spec string, cmd Job) error {schedule, err := Parse(spec)if err != nil {return err}c.Schedule(schedule, cmd)return nil
}
会首先解析时间表,如果填写有问题会直接 err,无误则将 func 添加到 Schedule 队列中等待执行
func (c *Cron) Schedule(schedule Schedule, cmd Job) {entry := &Entry{Schedule: schedule,Job: cmd,}if !c.running {c.entries = append(c.entries, entry)return}c.add <- entry
}
3、c.Start()
在当前执行的程序中启动 Cron 调度程序。其实这里的主体是 goroutine + for + select + timer 的调度控制哦
func (c *Cron) Run() {if c.running {return}c.running = truec.run()
}
time.NewTimer + for + select + t1.Reset
如果你是初学者,大概会有疑问,这是干嘛用的?
**(1)time.NewTimer **
会创建一个新的定时器,持续你设定的时间 d 后发送一个 channel 消息
(2)for + select
阻塞 select 等待 channel
(3)t1.Reset
会重置定时器,让它重新开始计时
注:本文适用于 “t.C 已经取走,可直接使用 Reset”。
总的来说,这段程序是为了阻塞主程序而编写的,希望你带着疑问来想,有没有别的办法呢?
有的,你直接 select{}
也可以完成这个需求 :)
验证
$ go run cron.go
2018/04/29 17:03:34 [info] replacing callback `gorm:update_time_stamp` from /Users/eddycjy/go/src/github.com/EDDYCJY/go-gin-example/models/models.go:56
2018/04/29 17:03:34 [info] replacing callback `gorm:update_time_stamp` from /Users/eddycjy/go/src/github.com/EDDYCJY/go-gin-example/models/models.go:57
2018/04/29 17:03:34 [info] replacing callback `gorm:delete` from /Users/eddycjy/go/src/github.com/EDDYCJY/go-gin-example/models/models.go:58
2018/04/29 17:03:34 Starting...
2018/04/29 17:03:35 Run models.CleanAllArticle...
2018/04/29 17:03:35 Run models.CleanAllTag...
2018/04/29 17:03:36 Run models.CleanAllArticle...
2018/04/29 17:03:36 Run models.CleanAllTag...
2018/04/29 17:03:37 Run models.CleanAllTag...
2018/04/29 17:03:37 Run models.CleanAllArticle...
检查输出日志正常,模拟已软删除的数据,定时任务工作 OK
小结
定时任务很常见,希望你通过本文能够熟知 Golang 怎么实现一个简单的定时任务调度管理
可以不依赖系统的 Crontab 设置,指不定哪一天就用上了呢
问题
如果你手动修改计算机的系统时间,是会导致定时任务错乱的,所以一般不要乱来。
参考
本系列示例代码
go-gin-example
我的公众号
Go Gin 系列十一:Cron定时任务相关推荐
- 【深入浅出Node.js系列十一】Node.js开发框架Express4.x
为什么80%的码农都做不了架构师?>>> #0 系列目录# 深入浅出Node.js系列 [深入浅出Node.js系列一]什么是Node.js [深入浅出Node.js系列二]N ...
- 数学之美 系列十一 - Google 阿卡 47 的制造者阿米特.辛格博士
数学之美 系列十一 - Google 阿卡 47 的制造者阿米特.辛格博士 枪迷或者看过尼古拉斯.凯奇(Nicolas Cage)主演的电影"战争之王"(Lord of War)的 ...
- 【深入浅出MyBatis系列十一】缓存源码分析
为什么80%的码农都做不了架构师?>>> #0 系列目录# 深入浅出MyBatis系列 [深入浅出MyBatis系列一]MyBatis入门 [深入浅出MyBatis系列二]配置 ...
- JAVA面试常考系列十一
转载自 JAVA面试常考系列十一 题目一 什么是JSP? JSP(Java Server Page)是一个文本文档,是一种将静态内容和动态生成内容混合在一起的技术. JSP包含两种类型的文本:静态数据 ...
- Debezium报错处理系列十一:Data row is smaller than a column index, internal schema representation is probabl
Debezium报错处理系列十一:Data row is smaller than a column index, internal schema representation is probably ...
- Python数据分析学习系列 十一 时间序列
Python数据分析学习系列 十一 时间序列 资料转自(GitHub地址):https://github.com/wesm/pydata-book 有需要的朋友可以自行去github下载 时间序列(t ...
- cron定时任务和No MTA installed, discarding output错误处理
陈拓 2021/09/09-2020/09/12 0. 我的系统 lsb_release -a 1. 设置cron 为了定时执行程序启用cron. 我的项目需求为每5分钟执行一次hkCapJpeg1. ...
- @Scheduled cron 定时任务表达式含义用法及* ?的区别
** @Scheduled cron 定时任务表达式含义用法及* ?的区别 ** cron格式:[秒数][分钟][小时][日期][月份][星期几][年份(可省略)] 关于[日期]与[星期几]的说明: ...
- Web前端开发人员和设计师必读文章【系列十一】
时光荏苒,转眼已是深秋,<Web 前端开发人员和设计师必读文章推荐[系列十一]>姗姗来迟.梦天空博客关注 前端开发 技术,分享各种增强网站用户体验的 jQuery 插件,展示前沿的 HTM ...
最新文章
- 海思3559A上编译OpenCV4.1.0源码操作步骤
- wp———跳转系统设置页面的wifi、网络连接、蓝牙、飞行模式等
- Java 基础 之 三目运算
- Auto Encoder用于异常检测
- 死磕java_死磕JavaScript-垃圾收集机制
- java泛型程序设计——通配符类型+通配符的超类型限定
- Vue通信、传值的多种方式,详解
- 汇博工业机器人码垛机怎么写_全自动码垛机器人在企业生产中的地位越来越重要...
- qgis折点打断_arcgis在折点处打断并建立网络分析(最短路径等问题)
- python classmethod用处_Python classmethod类方法修饰符
- extjs的panel怎么自适应高度_Ext Js自适应高度
- python,无网、没网、生成环境迁移安装环境,支持virtualenv
- 利用内存分析工具(Memory Analyzer Tool,MAT)分析java项目内存泄露
- Windows下jmeter安装
- 论文期刊科普-SCI SSCI CSSCI CSCD和北大核心期刊分别是什么?
- c语言全局变量global,C语言定义共享全局变量
- blockly -- 颜色(Block colour)
- c盘是不是越大越好_C盘下的pagefile文件是不是越大越好?
- 休闲实用英语:别误会这些英文的意思
- 安装Kali Linux渗透系统