Go语言封装Cron定时任务

Go语言封装Cron定时任务

介绍

在现代应用中,定时任务是非常常见的需求,无论是用于定时清理数据、定时发送邮件,还是定时执行系统维护任务。Go语言作为一门现代编程语言,提供了多种方法来实现定时任务。本文将重点介绍如何在Go中封装一个Cron定时任务管理器,帮助开发者高效管理定时任务。

目标

我们将通过使用 github.com/robfig/cron/v3 库来实现一个简洁、灵活的定时任务调度器。该库支持基于 Cron 表达式的任务调度,我们将基于该库封装出一个简单的 API,供开发者在实际项目中使用。

项目背景

Cron 表达式是一种用来表示时间计划的格式,它通常由 5 或 6 个字段组成,表示一个特定的时间点或时间间隔。Go中的 robfig/cron 库提供了非常便利的接口来处理这些表达式,并能够定期执行任务。

我们的目标是封装一个 Crontab 结构体,它将管理所有的定时任务,支持任务的添加、删除、查询以及启动和停止功能。

代码分析

下面是一个简单的 Cron 定时任务调度器的封装代码。它基于 robfig/cron 库并扩展了一个 Crontab 结构体,提供了一些常用的操作方法。

代码实现

go 复制代码
package crontab

import (
	"github.com/pkg/errors"
	cron "github.com/robfig/cron/v3"
	"sync"
)

// Crontab crontab struct
type Crontab struct {
	inner *cron.Cron
	ids   map[string]cron.EntryID
	mutex *sync.RWMutex
}

// NewCrontab new crontab
func NewCrontab() *Crontab {
	return &Crontab{
		inner: cron.New(cron.WithSeconds()), // 支持秒级别的Cron表达式
		ids:   make(map[string]cron.EntryID),
		mutex: new(sync.RWMutex),
	}
}

// IDs 获取所有有效的Cron任务ID
func (c *Crontab) IDs() []string {
	c.mutex.RLock()
	defer c.mutex.RUnlock()

	validIDs := make([]string, 0, len(c.ids))
	invalidIDs := make([]string, 0)
	for sid, eid := range c.ids {
		if e := c.inner.Entry(eid); e.ID != eid {
			invalidIDs = append(invalidIDs, sid)
			continue
		}
		validIDs = append(validIDs, sid)
	}

	// 清理无效的任务ID
	for _, id := range invalidIDs {
		delete(c.ids, id)
	}

	return validIDs
}

// Start 启动定时任务调度器
func (c *Crontab) Start() {
	c.inner.Start()
}

// Stop 停止定时任务调度器
func (c *Crontab) Stop() {
	c.inner.Stop()
}

// DelByID 根据ID删除定时任务
func (c *Crontab) DelByID(id string) error {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	eid, ok := c.ids[id]
	if !ok {
		return errors.Errorf("crontab id not exists!")
	}
	c.inner.Remove(eid)
	delete(c.ids, id)

	return nil
}

// AddByID 根据ID添加定时任务
// spec 是Cron表达式,cmd 是执行的任务
func (c *Crontab) AddByID(id, spec string, cmd cron.Job) error {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	if _, ok := c.ids[id]; ok {
		return errors.Errorf("crontab id exists!")
	}
	eid, err := c.inner.AddJob(spec, cmd)
	if err != nil {
		return err
	}
	c.ids[id] = eid
	return nil
}

// AddByFunc 根据ID添加函数作为定时任务
func (c *Crontab) AddByFunc(id, spec string, f func()) error {
	c.mutex.Lock()
	defer c.mutex.Unlock()

	if _, ok := c.ids[id]; ok {
		return errors.Errorf("crontab id exists!")
	}
	eid, err := c.inner.AddFunc(spec, f)
	if err != nil {
		return err
	}
	c.ids[id] = eid
	return nil
}

// IsExists 判断某个任务ID是否已存在
func (c *Crontab) IsExists(jid string) bool {
	c.mutex.RLock()
	defer c.mutex.RUnlock()

	_, exist := c.ids[jid]
	return exist
}

主要功能

  • NewCrontab(): 初始化一个新的 Crontab 实例,内部使用 cron.New() 来创建一个 Cron 调度器,支持秒级别的 Cron 表达式。

  • IDs(): 获取当前所有有效的定时任务ID。会清理掉无效的任务ID。

  • Start(): 启动 Cron 调度器,开始执行所有的定时任务。

  • Stop(): 停止 Cron 调度器,暂停定时任务的执行。

  • DelByID(id): 根据任务ID删除定时任务。

  • AddByID(id, spec, cmd): 根据 Cron 表达式添加一个新的定时任务。任务ID必须唯一。

  • AddByFunc(id, spec, f): 将一个函数作为定时任务来添加,使用 Cron 表达式来指定执行频率。

  • IsExists(jid): 判断某个定时任务ID是否存在。

Cron表达式解析

Cron 表达式是定时任务调度中常见的表示方式,它由五个或六个字段组成,每个字段代表一个时间单位。标准的 Cron 表达式格式如下:

scss 复制代码
* * * * * *
│ │ │ │ │ │
│ │ │ │ │ └─ 星期几 (0 - 7) (0或7代表星期天)
│ │ │ │ └──── 月份 (1 - 12)
│ │ │ └────── 日 (1 - 31)
│ │ └──────── 小时 (0 - 23)
│ └────────── 分钟 (0 - 59)
└──────────── 秒 (0 - 59)

例子

scss 复制代码
* * * * * *:每秒执行一次任务
0 * * * * *:每分钟的第0秒执行一次任务
0 0 * * * *:每天午夜执行一次任务
0 0 1 * * *:每月的第一天执行一次任务

使用示例

以下是如何使用封装好的 Crontab 类型来管理定时任务的示例:

go 复制代码
package main

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

func main() {
	// 创建一个新的 Crontab 实例
	c := crontab.NewCrontab()

	// 定义一个定时任务
	task := func() {
		fmt.Println("Task executed at", time.Now())
	}

	// 添加定时任务
	err := c.AddByFunc("task1", "*/5 * * * * *", task) // 每5秒执行一次
	if err != nil {
		fmt.Println("Error adding task:", err)
		return
	}

	// 启动任务调度器
	c.Start()

	// 等待一段时间后停止
	time.Sleep(20 * time.Second)
	c.Stop()

	// 删除任务
	err = c.DelByID("task1")
	if err != nil {
		fmt.Println("Error deleting task:", err)
	}
}

总结

通过使用 robfig/cron 库并封装成一个简单易用的 Crontab 类型,我们可以非常方便地在 Go 项目中管理定时任务。Cron 表达式为我们提供了灵活的时间配置,帮助开发者应对复杂的定时任务调度需求。

在实际应用中,我们可以根据需要扩展 Crontab 类型,支持更多功能,如任务状态监控、任务重试等,进一步提高定时任务管理的效率。

相关推荐
苏三说技术37 分钟前
Claude Code从失控到起飞,只用了这些技巧
后端
长栎2 小时前
写 for 循环写了十年,你却从没用过迭代器模式最狠的那一面
后端
LiaCode2 小时前
Redis 在生产项目的使用
前端·后端
用户559822481222 小时前
Docker Compose Down 导致容器数据误删——ext4 日志恢复全记录
后端
LiaCode2 小时前
一天学完 redis 的爽翻版核心知识总结
前端·后端
大刚测试开发实战2 小时前
如何内网穿透访问本地私有化部署的TestHub
前端·后端·github
xiaodaoluanzha2 小时前
迄今為止,最簡單的編程語言 Nolang
前端·后端
Csvn2 小时前
Docker 容器管理入门 — 从镜像到容器编排
后端
用户762352425912 小时前
ShardingJDBC
后端
行者全栈架构师2 小时前
IDEA 中 Maven 项目的 15 个红色报错快速解决方法
java·后端