Go实用工具包:定时任务管理神器 `robfig/cron`


在Go语言开发中,定时任务是一个常见的需求,无论是定时数据同步、日志清理、监控检查还是其他周期性任务,一个高效且易于使用的定时任务库是必不可少的。今天,我们将深入探讨一个广泛使用的Go定时任务库——robfig/cron,并结合实际代码示例,帮助你更好地理解和应用它。

一、快速入门

首先,我们需要安装robfig/cron库。你可以使用以下命令进行安装:

go get github.com/robfig/cron/v3

接下来,我们通过一个简单的示例来快速上手:

package main

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

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

	// 添加一个每分钟执行一次的任务
	c.AddFunc("* * * * * ", func() {
		fmt.Println("每分钟执行一次")
	})

	// 启动cron调度器
	c.Start()

	// 阻塞主线程,防止程序退出
	select {}
}

在这个示例中,我们创建了一个新的cron调度器,并添加了一个每分钟执行一次的任务。c.Start()启动调度器后,程序会一直运行,直到被手动终止。

二、Cron表达式详解

Cron表达式是一种用于指定定时任务执行时间的字符串格式。robfig/cron支持标准的Cron表达式格式,同时也提供了一些预定义的时间规则,方便使用。

1. 标准Cron表达式

标准的Cron表达式由6个字段组成,分别表示秒、分、时、日、月、周。例如:

  • "0 30 10 * * *":每天10点30分执行
  • "0 0 12 * * 1-5":每周一到周五12点执行
  • "0 0 0 1 * *":每月1号0点执行

2. 预定义规则

robfig/cron还提供了一些预定义的时间规则,方便快速设置常见的定时任务:

  • @yearly:每年1月1日0点执行
  • @monthly:每月1日0点执行
  • @daily:每天0点执行
  • @hourly:每小时0分执行
  • @every <duration>:每隔一段时间执行一次,例如@every 1h30m

示例代码:

c.AddFunc("@every 1h", func() {
    fmt.Println("每小时执行一次")
})

三、高级功能

1. 任务拦截器

任务拦截器允许你在任务执行前后添加自定义逻辑,例如日志记录、性能监控等。robfig/cron提供了WithChain方法来实现这一点。

示例代码:

var myWrapper cron.JobWrapper = func(j cron.Job) cron.Job {
	return cron.FuncJob(func() {
		start := time.Now()
		j.Run()
		defer func() {
			fmt.Printf("任务执行耗时: %v\n", time.Since(start))
		}()
	})
}

func main() {
	c := cron.New(
		cron.WithChain(
			myWrapper,
		),
	)

	c.AddFunc("@every 1m", func() {
		fmt.Println("每分钟执行一次")
	})

	c.Start()
	select {}
}

2. 动态任务管理

你可以动态地添加或删除任务。AddFuncAddJob方法返回一个EntryID,你可以使用这个ID来管理任务。

示例代码:

entryID, _ := c.AddFunc("@every 1m", func() {
    fmt.Println("每分钟执行一次")
})

// 删除任务
c.Remove(entryID)

3. 分布式锁集成

在分布式环境中,确保定时任务不会被多个实例重复执行是很重要的。robfig/cron支持通过分布式锁 来实现这一点。

示例代码:

func WithLocker(ctx context.Context, locker *redislock.Client) func(job cron.Job) cron.Job {
	return func(job cron.Job) cron.Job {
		return cron.FuncJob(func() {
			lock, err := locker.Obtain(ctx, "my-key", 100*time.Millisecond, nil)
			if errors.Is(err, redislock.ErrNotObtained) {
				return
			} else if err != nil {
				log.Fatalln(err)
				return
			}
			defer lock.Release(ctx)
			job.Run()
		})
	}
}
func main() {
	client := redis.NewClient(&redis.Options{
		Network: "tcp",
		Addr:    "127.0.0.1:6379",
	})
	defer client.Close()

	// Create a new lock client.
	locker := redislock.New(client)

	ctx := context.Background()

	c := cron.New(
		cron.WithChain(
			WithLocker(ctx, locker),
		),
	)

	c.AddFunc("* * * * *", func() {
		fmt.Println("每分钟执行一次")
	})

	c.Start()
	select {}
}

四、常见问题解答

1. 任务执行时间不准确

确保你的Cron表达式正确,并且时区设置正确。你可以通过WithLocation方法来设置时区。

示例代码:

c := cron.New(
    cron.WithLocation(time.FixedZone("CST", 8*3600)),
)

2. 任务panic导致程序崩溃

使用cron.Recover中间件可以捕获任务中的panic,防止程序崩溃。

3. 如何控制任务并发

使用SkipIfStillRunning中间件可以避免任务并发执行。

七、总结

robfig/cron是一个功能强大且易于使用的Go定时任务库,适用于各种场景。通过本文的介绍,希望你能够更好地理解和应用robfig/cron,提高开发效率。

wx

关注公众号

©2017-2023 鲁ICP备17023316号-1 Powered by Hugo