51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

golang定时任务

# golang 定时任务 {#golang-定时任务}

本文讲述 golang 中如何管理定时任务。原生的定时任务功能不好用也不强大,这里推荐 github.com/rfyiamcool/cronlib,该库支持动态添加、修改、删除定时任务,最具特色的功能是可以为每个定时任务指定唯一的标识 ID,该功能很实用,然而在当前最火的定时任务库 github.com/robfig/cron 上却没有(实际上 cronlib 就是基于 robfig 开发的)。所以本文强烈推荐 github.com/rfyiamcool/cronlib。

# 1. 封装 1 个通用的定时任务处理文件 {#_1-封装-1-个通用的定时任务处理文件}

为了方便调用,创建一个 cron_task.go 文件,里面封装了通用的定时任务处理逻辑。

package cron

import (
	"apiproject/config"
	"apiproject/log"
	"errors"

	"github.com/rfyiamcool/cronlib"
	"go.uber.org/zap"
)

type CallbackTask func(paraMap *map[string]interface{})

var MyCronSchduler *cronlib.CronSchduler

/**
启动定时任务列表
*/
func Init() {
	//任务开关是否开启
	if !config.GlobalConfig.TaskSwitchOn {
		log.Logger.Info("启动定时任务列表, 任务开关没有开启")
		return
	}

	MyCronSchduler = cronlib.New()
	MyCronSchduler.Start()
}

/**
注册定时任务
*/
func RegisterTask(jobName string, jobSpec string,
	callbackTask CallbackTask, callbackParaMap *map[string]interface{}) error {
	//检测定时任务是否已存在
	if IsExistTask(jobName) {
		log.Logger.Error("注册定时任务, 定时任务已存在", zap.Any("jobName", jobName))
		return errors.New("定时任务已存在")
	}

	//创建定时任务
	job, err := cronlib.NewJobModel(
		jobSpec,
		func() {
			log.Logger.Info("定时任务开始执行", zap.Any("jobName", jobName), zap.Any("jobSpec", jobSpec))
			callbackTask(callbackParaMap)
			log.Logger.Info("定时任务执行完成", zap.Any("jobName", jobName), zap.Any("jobSpec", jobSpec))
		},
	)
	if err != nil {
		return err
	}

	//注册定时任务
	err = MyCronSchduler.DynamicRegister(jobName, job)
	if err != nil {
		return err
	}

	log.Logger.Info("注册定时任务", zap.String("jobName", jobName), zap.String("jobSpec", jobSpec))
	return nil
}

/**
更新定时任务
*/
func UpdateTask(jobName string, jobSpec string,
	callbackTask CallbackTask, callbackParaMap *map[string]interface{}) error {
	//创建定时任务
	job, err := cronlib.NewJobModel(
		jobSpec,
		func() {
			log.Logger.Info("定时任务开始执行", zap.Any("jobName", jobName), zap.Any("jobSpec", jobSpec))
			callbackTask(callbackParaMap)
			log.Logger.Info("定时任务执行完成", zap.Any("jobName", jobName), zap.Any("jobSpec", jobSpec))
		},
	)
	if err != nil {
		return err
	}

	//更新定时任务
	err = MyCronSchduler.UpdateJobModel(jobName, job)
	if err != nil {
		return err
	}

	log.Logger.Info("更新定时任务", zap.String("jobName", jobName), zap.String("jobSpec", jobSpec))
	return nil
}

/**
反注册定时任务
*/
func UnRegisterTask(jobName string) error {
	if err := MyCronSchduler.UnRegister(jobName); err != nil {
		log.Logger.Error("反注册定时任务, 失败", zap.Any("jobName", jobName), zap.Error(err))
		return err
	}

	return nil
}

/**
是否存在某定时任务
*/
func IsExistTask(jobName string) bool {
	_, err := MyCronSchduler.GetServiceCron(jobName)
	log.Logger.Info("是否存在某定时任务", zap.Any("jobName", jobName), zap.Any("exist", err == nil))

	return err == nil
}

说明:

  • Init函数 需要在应用启动时手动调用该函数,完成全局定时任务管理器的初始化。
  • 定时任务的属性
    可以指定定时任务的 ID、定时表达式、回调函数、传给回调函数的参数。

# 2. 初始化 {#_2-初始化}

系统启动时, 调用前文的 Init 方法, 完成全局定时任务管理器的初始化。

# 3. 创建定时任务 {#_3-创建定时任务}

此处提供 2 个例子。

# 3.1 例 1 {#_3-1-例-1}

	err := cron.RegisterTask("爬取新闻数据", config.GlobalConfig.TaskCrawnewslistCron, s_spider.SpiderService.CrawNewsListTask, nil)
	if err != nil {
		panic(err)
	}

# 3.2 例 2 {#_3-2-例-2}

/**
注册重访上线定时任务
*/
func (this *revisitService) registerRevisitOnlineTask(distributor *m_distributor.Distributor) error {
	jobName := this.getRevisitOnlineJobName(distributor.ID)
	paraMap := map[string]interface{}{}
	paraMap["did"] = distributor.ID

	//反注册
	if cron.IsExistTask(this.getRevisitOnlineJobName(distributor.ID)) {
		if err := cron.UnRegisterTask(this.getRevisitOnlineJobName(distributor.ID)); err != nil {
			log.Logger.Error("注册重访上线定时任务, 反注册失败", zap.Any("did", distributor.ID), zap.Error(err))
			return errors.New("反注册失败")
		}
		log.Logger.Info("注册重访上线定时任务, 当前任务已存在", zap.Any("did", distributor.ID))
	}

	//注册
	if distributor.RevisitOnlineTime != "" {
		if err := cron.RegisterTask(jobName, distributor.RevisitOnlineTime, this.RevisitOnlineTaskCallback, &paraMap); err != nil {
			log.Logger.Error("注册重访上线定时任务, 失败", zap.Any("jobName", jobName), zap.Any("did", distributor.ID), zap.Error(err))
			return err
		}
		log.Logger.Info("注册重访上线定时任务, 完成", zap.Any("distributor", distributor))
	}

	return nil
}

# 4 参考资料 {#_4-参考资料}

详细用法详见cronlib 的官网 (opens new window)
cronlib 是基于robfig (opens new window)开发而来。robfig 是最火的定时任务库,但是我觉得封装之后的 cronlib 变得更好用。

赞(0)
未经允许不得转载:工具盒子 » golang定时任务