手把手带你从0到1封装Gin框架:11 crontab

634 阅读2分钟

项目源码

Github

定时任务本质就是在指定的时间执行一个命令,通常我们会借助Linux系统的crontab去实现,或者借助第三方软件去实现配置和调用,这两种都比较麻烦,需要去服务器配置或者多部署一个应用,在golang项目中,我们可以通过直接在项目中集成的方式来实现

安装

go get github.com/robfig/cron/v3

基本使用

官方文档

c := cron.New()
c.AddFunc("0 30 * * * *", func() { fmt.Println("Every hour on the half hour") })
c.AddFunc("@hourly",      func() { fmt.Println("Every hour") })
c.AddFunc("@every 1h30m", func() { fmt.Println("Every hour thirty") })
c.Start()
..
// Funcs are invoked in their own goroutine, asynchronously.
...
// Funcs may also be added to a running Cron
c.AddFunc("@daily", func() { fmt.Println("Every day") })
..
// Inspect the cron job entries' next and previous run times.
inspect(c.Entries())
..
c.Stop()  // Stop the scheduler (does not stop any jobs already running).

从官方文档可以看到执行的规则spec是支持多种写法的,最低可以支持秒级运行,也兼容Linux系统crontab的写法

下边再看一下简单使用:

import (
	"fmt"
	"github.com/robfig/cron/v3"
)

func main() {
	c := cron.New()

	c.Start()
	defer c.Stop()

	_, err := c.AddFunc("@every 3s", func() {
		fmt.Println("@every 3s 执行开始")
	})

	_, err = c.AddFunc("@every 4s", func() {
		fmt.Println("@every 4s 执行开始")
	})

	if err != nil {
		fmt.Println(err)
		return
	}

	select {}
}

运行之后可以看到控制台定时输出内容

项目中集成

首先,创建crontab需要用到的类型和接口,创建internal/crontab/crontab.go文件:

package crontab

import (
	"github.com/robfig/cron/v3"
)

// Init 函数用于初始化一个 Crontab 实例
func Init() *Crontab {
	c := &Crontab{
		cron: cron.New(),
	}

	return c
}

// Crontab 类型
type Crontab struct {
	cron *cron.Cron
}

// TaskInterface 任务接口
type TaskInterface interface {
	Spec() string
	Fn() func()
}

// Start 启动crontab服务
func (c *Crontab) Start() {
	c.cron.Start()
}

// Stop 停止crontab服务
func (c *Crontab) Stop() {
	c.cron.Stop()
}

// AddTask 添加任务
func (c *Crontab) AddTask(tasks ...TaskInterface) {
	if len(tasks) == 0 {
		return
	}

	for _, task := range tasks {
		_, err := c.cron.AddFunc(task.Spec(), task.Fn())
		if err != nil {
			return
		}
	}
}

接着,定义一下全局变量,修改internal/global/global.go文件:

package global

import (
	"eve/internal/config"
	"eve/internal/crontab"
	"eve/internal/event"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

var (
	Config          *config.Config
	DB              *gorm.DB
	Logger          *zap.Logger
	EventDispatcher *event.Dispatcher
	Crontab         *crontab.Crontab
)

然后,创建具体的task文件,新增app/task/foo_task.go文件:

package task

import "fmt"

type FooTask struct{}

func (f *FooTask) Spec() string {
	return "@every 3s"
}

func (f *FooTask) Fn() func() {
	return func() {
		fmt.Println("foo task executed")
	}
}

再定义一个统一返回需要注册的task的合集的方法,新增app/task/task.go文件:

package task

import "eve/internal/crontab"

func Tasks() []crontab.TaskInterface {
	return []crontab.TaskInterface{
		&FooTask{},
	}
}

最后,在internal/bootstrap/init.go init方法中新增定时任务初始化逻辑:

func init() {
	...

	// 初始化定时任务
	global.Crontab = crontab.Init()
	global.Crontab.AddTask(task.Tasks()...)
	global.Crontab.Start()
}

代码修改完成,启动项目就可以看到控制台有输出,foo_task被执行了

总结

  • cron库安装
  • 基本使用
  • 在项目中集成

commit-hash: 58b65281