golang定时器实现 Golang如何对cron进行二次封装实现指定时间执行定

golang定时器实现 Golang如何对cron进行二次封装实现指定时间执行定

目录
  • 背景
  • cron库下载
  • 代码示例
    • 1结构体定义
    • 2定时任务开启
    • 3使用示例
    • 4控制台输出
  • 拓展资料

    背景

    go中常用的定时任务库:https://github.com/robfig/cron,不支持指定某个时刻开始执行一次任务,接着再以一定的时刻间隔开始执行任务。

    在诚实的业务场景中可能会有这样的需求:进行某个操作时执行一次任务,接着根据这个操作时刻每隔一段时刻执行一次任务;再次操作时,立即执行一次任务,接着根据此次操作的时刻点每隔一段时刻执行一次任务,这时就需要停止上一次操作产生的定时刻隔执行任务。

    下面就根据go中的cron库进行封装来满足上述场景的功能。

    cron库下载

    go get -u github.com/robfig/cron/v3

    代码示例

    1结构体定义

    import ( “fmt” “sync” “time” “GoTest/comm/logger” “github.com/robfig/cron/v3” “go.uber.org/zap”)const ( HOUR = 1 MINUTE = 2 SECOND = 3)const defaultIntervalTime = 8type VarCron struct c cron.Cron jobId cron.EntryID //执行的任务id jobMutex sync.Mutex //防止并发难题 startTime time.Time //定时任务从此时刻开始执行 intervalTime uint32 //任务执行间隔时刻,不设置默认8小时 intervalType uint8 //任务执行间隔类型,1-时,2.分,3-秒,不设置默认单位为时 f func() error //要执行的任务}type OpOption func(VarCron)func NewVarCron(f func() error, opts …OpOption) VarCron vc := &VarCron c: cron.New(cron.WithSeconds()), //支持秒级调度 f: f, } for _, opt := range opts opt(vc) } return vc}func WithIntervalTime(intervalTime uint32) OpOption return func(vc VarCron) vc.intervalTime = intervalTime }}func WithIntervalType(intervalType uint8) OpOption return func(vc VarCron) vc.intervalType = intervalType }}

    上面定义一个新的结构体VarCron就是给原生的cron对象增加一些新的属性字段。

    字段 含义
    jobId 定时执行任务的id,只支持一个任务,目的是为了方便管理,如果想支持多个,可以多使用NewVarCron初始化多个对象分别执行各自的定时任务
    jobMutex 保证并发安全
    startTime 首次执行任务的时刻
    intervalTime 定时任务执行间隔
    intervalType 定时任务执行类型
    f 定时任务中执行的函数

    2定时任务开启

    func (v VarCron) Start(startTime time.Time) v.jobMutex.Lock() //保证同一时刻只有一个在执行 defer v.jobMutex.Unlock() logger.Info(“start var cron”, zap.Time(“last_start_time”, v.startTime), zap.Time(“this_start_time”, startTime)) //更新开始时刻 v.startTime = startTime //停止上一次的定时任务 v.stop() now := time.Now() if now.After(v.startTime) || now.Equal(v.startTime) //定时任务指定的执行时刻在此刻之前就立即执行 logger.Info(“now time after or equal start time”, zap.Time(“now_time”, now), zap.Time(“start_time”, v.startTime)) //立即执行一次 v.execJob() //间隔执行定时任务 jobId, err := v.c.AddFunc(v.getInterval(), func() v.execJob() }) if err != nil logger.Error(“add func error”, zap.Error(err)) return } v.jobId = jobId //开始定时任务 v.c.Start() } else logger.Info(“now time before start time”, zap.Time(“now_time”, now), zap.Time(“start_time”, v.startTime)) //到指定时刻时刻之后再开始执行定时任务,精确到某月某天某时某分某秒就行 jobId, err := v.c.AddFunc(fmt.Sprintf(“%d %d %d %d %d ?”, v.startTime.Second(), v.startTime.Minute(), v.startTime.Hour(), v.startTime.Day(), v.startTime.Month()), func() //停止上一次的定时任务 v.stop() //这次是到指定时刻之后的执行 v.execJob() //根据间隔开启定时任务 newJobId, err := v.c.AddFunc(v.getInterval(), func() v.execJob() }) if err != nil logger.Error(“add func error”, zap.Error(err)) return } v.jobId = newJobId v.c.Start() }) if err != nil logger.Error(“add func error”, zap.Error(err)) return } v.jobId = jobId v.c.Start() }}func (v VarCron) stop() if v.c != nil v.c.Remove(v.jobId) //移除任务 v.c.Stop() //关闭定时任务 }}func (v VarCron) execJob() if err := v.f(); err != nil logger.Error(“exec job error”, zap.Error(err)) }}func (v VarCron) getInterval() string if v.intervalTime == 0 v.intervalTime = defaultIntervalTime } switch v.intervalType case HOUR: return fmt.Sprintf(“@every %dh”, v.intervalTime) case MINUTE: return fmt.Sprintf(“@every %dm”, v.intervalTime) case SECOND: return fmt.Sprintf(“@every %ds”, v.intervalTime) } return fmt.Sprintf(“@every %dh”, v.intervalTime)}

    调用Start(startTime time.Time)函数会有两种场景:

    • 场景1:startTime在当前时刻之前,这个时候会立即执行一次任务,接着按照间隔定时执行任务。
    • 场景2:startTime在当前时刻之后,这个时候会等待时刻到达startTime执行一次,接着按照间隔定时执行任务。

    上面代码中的stop函数目的就是为了停止上一次的任务,保证不会有冲突的定时任务执行。

    3使用示例

    f := func() error logger.Info(“exec task”) return nil } //每30秒打印一次时刻 varCron := self_cron.NewVarCron(f, self_cron.WithIntervalType(self_cron.SECOND), self_cron.WithIntervalTime(30)) fmt.Println(“===== 指定开始时刻在当前时刻之前,会立即执行一次,接着定时执行 ======”) varCron.Start(time.Now().AddDate(0, 0, -1)) //AddDate(0, 0, -1)的影响是将日期向前推一天 time.Sleep(3 time.Minute) //第一种场景定时执行任务跑三分钟 fmt.Println(“===== 指定开始时刻在当前时刻之后,到指定时刻执行一次,接着再开始定时执行 ======”) varCron.Start(time.Now().Add(time.Minute)) //一分钟后立即执行一次,接着开始定时执行 time.Sleep(3 time.Minute) //第二种场景定时执行任务跑三分钟就退出

    上面一个简单使用的例子:注册一个每隔30秒打印字符串exec task的函数;第1次指定开始时刻为昨天的这个时刻,这时会立即打印exec task一次,接着每隔30s打印一次exec task;3分钟后第2次指定开始时刻为当前时刻的1分钟之后,这时上一次的任务已经被取消,1分钟内不会再打印exec task,1分钟后会打印exec task,接着每隔30s打印一次exec task

    4控制台输出

    $ go run ./cron_demo/main.go===== 指定开始时刻在当前时刻之前,会立即执行一次,接着定时执行 ======[2024-10-08 17:23:38.135] | INFO | Goroutine:1 | [self_cron/start_cron.go:63] | start var cron | “last_start_time”: “[0001-01-01 00:00:00.000]”, “this_start_time”: “[2024-10-07 17:23:38.096]”}[2024-10-08 17:23:38.136] | INFO | Goroutine:1 | [self_cron/start_cron.go:73] | now time after or equal start time | “now_time”: “[2024-10-08 17:23:38.136]”, “start_time”: “[2024-10-07 17:23:38.096]”}[2024-10-08 17:23:38.136] | INFO | Goroutine:1 | [cron_demo/main.go:159] | exec task //指定的执行时刻在当前时刻之前,立即执行一次,之后每隔30s执行[2024-10-08 17:24:08.013] | INFO | Goroutine:34 | [cron_demo/main.go:159] | exec task[2024-10-08 17:24:38.008] | INFO | Goroutine:35 | [cron_demo/main.go:159] | exec task[2024-10-08 17:25:08.010] | INFO | Goroutine:36 | [cron_demo/main.go:159] | exec task[2024-10-08 17:25:38.008] | INFO | Goroutine:37 | [cron_demo/main.go:159] | exec task[2024-10-08 17:26:08.015] | INFO | Goroutine:38 | [cron_demo/main.go:159] | exec task[2024-10-08 17:26:38.005] | INFO | Goroutine:39 | [cron_demo/main.go:159] | exec task===== 指定开始时刻在当前时刻之后,到指定时刻执行一次,接着再开始定时执行 ======[2024-10-08 17:26:38.144] | INFO | Goroutine:1 | [self_cron/start_cron.go:63] | start var cron | “last_start_time”: “[2024-10-07 17:23:38.096]”, “this_start_time”: “[2024-10-08 17:27:38.144]”} [2024-10-08 17:26:38.145] | INFO | Goroutine:1 | [self_cron/start_cron.go:92] | now time before start time | “now_time”: “[2024-10-08 17:26:38.145]”, “start_time”: “[2024-10-08 17:27:38.144]”}[2024-10-08 17:27:38.003] | INFO | Goroutine:5 | [cron_demo/main.go:159] | exec task //指定时刻到了之后才执行,之后每隔30s执行[2024-10-08 17:28:08.007] | INFO | Goroutine:42 | [cron_demo/main.go:159] | exec task[2024-10-08 17:28:38.008] | INFO | Goroutine:43 | [cron_demo/main.go:159] | exec task[2024-10-08 17:29:08.013] | INFO | Goroutine:44 | [cron_demo/main.go:159] | exec task[2024-10-08 17:29:38.013] | INFO | Goroutine:45 | [cron_demo/main.go:159] | exec task

    拓展资料

    上面给出一个指定一个时刻开始执行任务,接着再以一定的时刻间隔定时执行任务的功能,可以根据业务场景的需求去修改上述功能,新增一些属性,比如除了动态修改定时任务时刻,还可以动态修改时刻间隔或执行函数,或者新增一个tag字段打印在日志中来区分不同的业务。

    以上为个人经验,希望能给大家一个参考,也希望大家多多支持风君子博客。

    无论兄弟们可能感兴趣的文章:

    • Golang定时任务框架GoCron的源码分析
    • 详解怎样使用Golang实现Cron定时任务
    • Golang实现CronJob(定时任务)的技巧详解
    • golang定时任务cron项目实操指南
    • Golangcron定时器和定时任务的使用场景
    • Golang Cron 定时任务的实现示例
    版权声明

    返回顶部