前言:
业务越来越复杂,有太多太多的定时任务需要管理,如事务检查,风控扫描,报表,日报等等。这些任务本身都是golang写的,所以需要一个基于golang开发的定时管理器。
如果只是需要定时器管理,我们可以直接用timer或者ticker,甚至自己用minHeap来实现。但传统的时间格式表现力一般,比如我需要每个周一和周三的上午来报表输出?所以需要crontab格式的支持。
该文章后续仍在不断的更新修改中, 请移步到原文地址 http://xiaorui.cc/?p=5625
在github里,比较火热的golang crontab库是 robfig/cron,花了些时间看了他的代码,crontab解析器写的没有问题,单元测试也很丰富,但是任务的调度有些粗糙,比如没有修改和停止定时任务。
我需要的定时任务管理是可以动态的对任务进行增删改查,这样才可以跟基于mysql数据库开发的配置系统结合在一起,方便的组织管理任务。robfig/cron 暂时还不能做这些功能。 所以,为了应对我的需求,我自己在robfig/cron库的基础上做了一些封装,俗称造轮子。 项目名很简单,叫cronlib 。
代码已经push到github了,地址 https://github.com/rfyiamcool/cronlib ,求 star !!!
golang cronlib有什么优点?
1. 线程安全
robfig/cron不是线程安全的,管理任务的slice存在并发安全的问题。cronlib是加锁的。
2. 修改任务的结构
不仅可以修改任务的时间,还可以修改回调方法等。
3. 停止任务
4. 增加异步和同步模式
一个任务的执行周期是1分钟调用一次,但是调用的方法发生block,耗时超过一分钟。如果异步模式,可能系统内存在两个协程在跑一个任务。当然,选择同步或异步,还需要业务上的考虑。
5. 增加join方法
优雅退出,只有在所有任务都退出后,才会return
go cronlib的使用例子
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
// xiaorui.cc package main // test for crontab spec import ( "log" "time" "github.com/rfyiamcool/cronlib" ) func main() { cron := cronlib.New() specList := map[string]string{ "risk.scan.total.1s": "*/1 * * * * *", "risk.scan.total.2s": "*/2 * * * * *", "risk.scan.total.3s": "*/3 * * * * *", "risk.scan.total.4s": "*/4 * * * * *", "risk.scan.total.5s.to.3s": "*/5 * * * * *", } for srv, spec := range specList { tspec := spec // copy ssrv := srv // copy job, err := cronlib.NewJobModel( spec, func() { stdout(ssrv, tspec) }, ) if err != nil { panic(err.Error()) } err = cron.Register(srv, job) if err != nil { panic(err.Error()) } } // update test time.AfterFunc(10*time.Second, func() { spec := "*/3 * * * * *" srv := "risk.scan.total.5s.to.3s" log.Println("reset 5s to 3s", srv) job, _ := cronlib.NewJobModel( spec, func() { stdout(srv, spec) }, ) cron.UpdateJobModel(srv, job) log.Println("reset finish", srv) }) // kill test time.AfterFunc(3*time.Second, func() { srv := "risk.scan.total.1s" log.Println("stoping", srv) cron.StopService(srv) log.Println("stop finish", srv) }) time.AfterFunc(11*time.Second, func() { srvPrefix := "risk" log.Println("stoping srv prefix", srvPrefix) cron.StopServicePrefix(srvPrefix) }) cron.Start() cron.Wait() } func stdout(srv, spec string) { log.Println(srv, spec) } |
需要说明的是cronlib库里crontab格式是支持秒的,一共6列,第一列是秒。linux系统的crontab只能支持到分钟,一共五列。 更多的go crontab的格式,大家可以参考下 https://github.com/robfig/cron 的godoc 。
另外我在cronlib的repo里放了一些例子,大家可以看看。 https://github.com/rfyiamcool/cronlib/tree/master/example
总结:
原本想不基于robfig/cron直接开发定时任务管理器,后来发现crontab格式解析太过繁琐,再加上一套完整的单元测试,太耗时间了,所以还是基于robfig/cron搞了。
现在只是把go cronlib库开源了,这个属于单机版了。如果后期在多节点场景下,还是需要有分布式控制及数据库的配置管理等。我会近期整理出一个版本,开源出去。
end.
有疑问加站长微信联系(非本文作者)