在GoFrame框架中优雅地实现定时任务

541 阅读4分钟

在使用GoFrame开发后台服务时,我们经常需要实现一些定时任务,比如:

  1. 每天凌晨进行一些数据统计和分析
  2. 定期清理过期的缓存数据
  3. 定时发送一些通知消息
  4. 定期执行一些数据备份

这些定时任务可以通过在代码中直接使用原生的time包、ticker来实现。不过GoFrame框架提供了一个gron模块,封装了更加简洁友好的定时任务API。下面我们具体看看如何使用。 首先在项目目录下执行:

go get github.com/gogf/gf/v2/os/gcron

安装gron模块。

然后在代码中这样使用:

package main

import (
    "github.com/gogf/gf/v2/frame/g"  
    "github.com/gogf/gf/v2/os/gcron"
    "time"
)

func main() {
    ctx := gctx.New()
    gcron.Add(ctx,"0 30 * * * *", func(ctx context.Context) { 
        g.Log().Info(ctx,"Every hour on the half hour") 
    })
    gcron.Add("15 * * * * *", func(ctx context.Context) { 
        g.Log().Info(ctx,"Every 15 seconds") 
    }) 
    gcron.Add("@hourly", func(ctx context.Context) { 
        g.Log().Info(ctx,"Every hour") 
    })
    gcron.Add("@every 1h30m", func(ctx context.Context) { 
        g.Log().Info(ctx,"Every hour thirty") 
    }) 
    g.Log().Info(ctx,"cron started")
    select {} 
}

gcron.Add方法用于添加定时任务,第一个参数是cron表达式,第二个参数是任务执行的函数。

cron表达式语法类似linux的crontab,从左到右分别表示:秒 分 时 日 月 星期

上面的例子中:

  • "0 30 * * * *" 表示每个小时的第30分钟(每小时执行一次)
  • "15 * * * * *" 表示每隔15秒执行一次
  • "@hourly"是预定义的宏,等同于"0 0 * * * *",表示每小时执行一次
  • "@every 1h30m"表示每隔1小时30分钟执行一次 除了使用gcron.Add动态添加任务,还可以将任务配置在配置文件中,例如:
cron:
  cron.job:
    - name: "task1"
      spec: "0 30 * * * *"
      command: "task1Command"
    - name: "task2"
      spec: "@every 1h30m"
      command: "task2Command"

可见,gron模块提供了简洁的API来管理定时任务,支持cron表达式、预定义的时间间隔宏等多种定义方式,也可以集成到GoFrame的配置管理中,是开发后台定时任务的利器。

处理执行失败

在处理定时任务时,我们需要考虑任务执行失败的情况。定时任务执行失败的原因可能有:

  1. 任务本身的代码逻辑有bug,比如空指针异常、数组越界等。
  2. 任务依赖的外部资源出现问题,比如网络中断、数据库连接失败等。
  3. 任务执行时间过长,超过了预期的时间。

在任务执行函数中添加recover机制

在gron定时任务的执行函数中,我们可以通过defer+recover机制来捕获任务执行过程中的panic异常,避免panic导致进程崩溃:

gcron.Add(ctx,"0 30 * * * *", func(ctx context.Context) {
    defer func() {
        if err := recover(); err != nil {
            // 记录错误日志
            g.Log().Errorf("panic recovered: %v", err)
        }
    }()
    // 任务逻辑
    // ...    
})

为任务设置超时时间

如果定时任务执行时间过长,超过了预期时间,可能会影响到其他任务的执行,或者占用过多系统资源。

任务执行失败重试

有些任务执行失败后,我们希望能够自动重试执行,直到成功为止。

任务执行失败告警通知

对于一些非常重要的定时任务,我们可能需要在任务执行失败时及时收到告警通知,以便快速排查问题。可以在任务执行函数中添加失败告警通知逻辑,例如:

gcron.Add(ctx,"0 30 * * * *", func(ctx context.Context) {
    defer func() {
        if err := recover(); err != nil {    
            g.Log().Errorf("panic recovered: %v", err)
            // 发送告警通知,如邮件、短信、微信等
            sendAlertNotification(err) 
        }
    }()
    // 任务逻辑
    // ...
})

定期检查任务执行状态

我们可以为gron设置一个统计日志的输出函数,定期输出各个任务的执行情况统计信息,包括成功次数、失败次数、执行时间等,以便我们及时了解任务的执行状态.

总结

在使用GoFrame框架中的gron模块实现定时任务时,我们可以通过简洁的API来管理任务。同时,为了提高任务的可靠性,我们需要处理任务执行失败的情况。通过添加recover机制、设置超时时间、重试策略、告警通知以及定期检查任务状态,我们可以更好地监控和优化定时任务的执行,确保系统的稳定性。