【Golang】定时任务Cron指南-毫秒级任务支持

2024-02-09 08:04

本文主要是介绍【Golang】定时任务Cron指南-毫秒级任务支持,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • Cron
    • Cron快速使用
    • 时间表达式
      • 最小分钟级任务
      • 最小秒级任务
      • 预定义的时间表
    • 时区
    • Job
    • 选项
      • Job 包装器
      • WithLogger
    • 支持毫秒级任务

Cron

版本:v3.0.0
仓库:https://github.com/robfig/cron

cron是golang实现定时任务比较好的库, 这个库提供了一个简单而强大的接口,用于创建和管理基于cron表达式的定时任务。cron库的主要特点有:

  • 基于cron表达式的任务调度
  • 多任务支持
  • 容错和错误处理
  • 可靠性
  • 易用的API
  • 灵活性
  • 并发安全

Cron快速使用

package mainimport ("fmt""github.com/robfig/cron/v3"
)func main() {job := cron.New()job.AddFunc("@every 1s", func() {fmt.Println("hello world")})job.Start()select {}
}

上述简单的示例表示,每秒钟执行一次hello world打印。其中容易让人产生困惑的是"@every 1s"的含义,这是一条描述定时任务执行的时间表达式,下面将会具体介绍。

时间表达式

cron库支持用 6 个空格分隔的域来表示时间(在v3版本中新增了对秒级任务的支持):

# ┌────────────── second (0–59)
# │ ┌───────────── minute (0–59)
# │ │ ┌───────────── hour (0–23)
# │ │ │ ┌───────────── day of the month (1–31)
# │ │ │ │ ┌───────────── month (1–12)
# │ │ │ │ │ ┌───────────── day of the week (0–6) (Sunday to Saturday;
# │ │ │ │ │ │                                   7 is also Sunday on some systems)
# │ │ │ │ │ │
# │ │ │ │ │ │
# * * * * * * <command to execute>
Field name   | Mandatory? | Allowed values  | Allowed special characters
----------   | ---------- | --------------  | --------------------------
Seconds      | Yes        | 0-59            | * / , -
Minutes      | Yes        | 0-59            | * / , -
Hours        | Yes        | 0-23            | * / , -
Day of month | Yes        | 1-31            | * / , - ?
Month        | Yes        | 1-12 or JAN-DEC | * / , -
Day of week  | Yes        | 0-6 or SUN-SAT  | * / , - ?
  • 星号 (*):星号表示 cron 表达式将匹配该字段的所有值;例如,在第 5 个字段(月份)中使用星号将表示每个月。
  • 斜杠 (/):斜杠用于描述范围的步长。例如,第2个字段(分钟)中的 3-59/15 表示该小时的第 3 分钟以及此后每 15 分钟一次。
  • 逗号 (,):逗号用于分隔列表中的项目。例如,在第 6 个字段(星期几)中使用“MON,WED,FRI”将表示星期一、星期三和星期五。
  • 连字符 (-):连字符用于定义范围。例如,在第 3 个字段(小时)9-17 表示上午 9 点到下午 5 点之间的每小时(含)。
  • 问号(?):只能用在月和周的域中,用来代替*,表示每月/周的任意一天。

最小分钟级任务

使用这种以空格分隔的域来表示时间的方式默认情况下只能支持到分钟级任务:

package mainimport ("fmt""github.com/robfig/cron/v3"
)func main() {job := cron.New()job.AddFunc("* * * * *", func() {fmt.Println("hello world")})job.Start()select {}
}

表示每分钟执行一次
注意:实测在v3.0.1版本6个*是不会执行任务的。
查看表达是是否正确:https://crontab.guru/

最小秒级任务

如果想要支持秒级任务,则需添加cron.WithSeconds选项:

package mainimport ("fmt""github.com/robfig/cron/v3"
)func main() {job := cron.New()job.AddFunc("* * * * * *", func() {fmt.Println("hello world")})job.Start()select {}
}

表示每秒执行一次
注意:添加了cron.WithSeconds后6个*可以正确执行。

预定义的时间表

可以使用几个预定义计划之一来代替 cron 表达式。

Entry                  | Description                                | Equivalent To
-----                  | -----------                                | -------------
@yearly (or @annually) | Run once a year, midnight, Jan. 1st        | 0 0 0 1 1 *
@monthly               | Run once a month, midnight, first of month | 0 0 0 1 * *
@weekly                | Run once a week, midnight between Sat/Sun  | 0 0 0 * * 0
@daily (or @midnight)  | Run once a day, midnight                   | 0 0 0 * * *
@hourly                | Run once an hour, beginning of hour        | 0 0 * * * *

还可以安排作业以固定的时间间隔执行,从添加作业或运行 cron 时开始。这是通过格式化 cron 规范来支持的,如下所示:

@every <duration>

其中“duration”time.ParseDuration 接受的字符串(http://golang.org/pkg/time/#ParseDuration)
例子:

c := cron.New()
c.AddFunc("@hourly",      func() { fmt.Println("Every hour") })
c.AddFunc("@every 1h30m", func() { fmt.Println("Every hour thirty") })
c.AddFunc("@every 1s", func() { fmt.Println("Every seconds") })
c.Start()

cron还提供了cron.Every方法,用于直接接收time.Duration来设置任务间隔:

package mainimport ("fmt""time""github.com/robfig/cron/v3"
)func main() {job := cron.New(cron.WithSeconds())job.Schedule(cron.Every(1*time.Second), cron.FuncJob(func() {fmt.Println("hello world")}))job.Start()select {}
}

时区

默认情况下任务是基于当前时区的,cron也可以设置不同的时区:

loLosAngeles, _ := time.LoadLocation("America/Los_Angeles")
job := cron.New(cron.WithLocation(loLosAngeles))
job.AddFunc("0 6 * * ?", func() {fmt.Println("Every 6 o'clock at Los Angeles")
})

或者:

job.AddFunc("CRON_TZ=Asia/Tokyo 0 6 * * ?", func() {fmt.Println("Every 6 o'clock at Tokyo")
})

Job

除了使用无参的回调方式,cron还提供了实现job接口的方式:

type Job interface {Run()
}

实现job接口

package mainimport ("fmt""time""github.com/robfig/cron/v3"
)func main() {job := cron.New(cron.WithSeconds())j := &myJob{}job.AddJob("@every 1s", j)job.Start()select {}
}type myJob struct {i int
}func (j *myJob) Run() {j.i++fmt.Println("hello world:", j.i)
}

执行结果:

hello world: 1
hello world: 2
hello world: 3
hello world: 4
hello world: 5
hello world: 6

选项

  • WithLocation:指定时区
  • WithParser:使用自定义的解析器
  • WithSeconds:让时间格式支持秒
  • WithLogger:自定义日志
  • WithChain:Job 包装器

Job 包装器

Job 包装器可以在执行实际的Job前后添加一些逻辑

cron库提供了一些常用的包装器:

  • cron.DelayIfStillRunning: 如果上周期的任务还在执行,则延迟此次并产生一条Info日志
  • cron.SkipIfStillRunning:如果上周期的任务还在执行,则跳过此次并产生一条Info日志
  • cron.Recover:捕获任务异常,并产生error日志

WithLogger

cron提供默认的标准输出日志打印cron.DefaultLogger和丢弃日志cron.DiscardLogger两种:

// DefaultLogger is used by Cron if none is specified.
var DefaultLogger Logger = PrintfLogger(log.New(os.Stdout, "cron: ", log.LstdFlags))// DiscardLogger can be used by callers to discard all log messages.
var DiscardLogger Logger = PrintfLogger(log.New(ioutil.Discard, "", 0))

也可是使用cron.PrintfLoggercron.VerbosePrintfLogger包装:

  • cron.PrintfLogger: 只打印错误日志
  • cron.VerbosePrintfLogger:打印详细日志
package mainimport ("fmt""github.com/robfig/cron/v3"
)func main() {job := cron.New(cron.WithLogger(cron.VerbosePrintfLogger(log.New(os.Stdout, "cron: ", log.LstdFlags),)),)job.AddFunc("@every 1s", func() {fmt.Println("hello world")})job.Start()select {}
}

支持毫秒级任务

cron库给出的方法最小只能支持到秒级任务,如果想要精确到毫秒级任务,则需要重新实现Schedule接口

// Schedule describes a job's duty cycle.
type Schedule interface {// Next returns the next activation time, later than the given time.// Next is invoked initially, and then each time the job is run.Next(time.Time) time.Time
}

自定义一个ConstantDelaySchedule结构体,并给出Every方法(这边我限制最小到200ms)

package cronimport "time"// ConstantDelaySchedule represents a simple recurring duty cycle, e.g. "Every 5 minutes".
// It does not support jobs more frequent than once a second.
type ConstantDelaySchedule struct {Delay time.Duration
}// Every returns a crontab Schedule that activates once every duration.
// Delays of less than a second are not supported (will round up to 1 second).
// Any fields less than a Second are truncated.
func Every(duration time.Duration) ConstantDelaySchedule {min := 200 * time.Millisecondif duration < min {duration = min}return ConstantDelaySchedule{Delay: duration,}
}// Next returns the next time this should be run.
// This rounds so that the next activation time will be on the second.
func (schedule ConstantDelaySchedule) Next(t time.Time) time.Time {return t.Add(schedule.Delay)
}

调用:

package mainimport ("fmt""time""github.com/robfig/cron/v3"
)func main() {job := cron.New(cron.WithSeconds())j := &myJob{t: time.Now(),}job.Schedule(Every(200*time.Millisecond), j)job.Start()select {}
}type myJob struct {i intt time.Time
}func (j *myJob) Run() {j.i++now := time.Now()sub := now.Sub(j.t)j.t = nowfmt.Printf("hello world: %d, duraction : %d ms \n", j.i, sub.Milliseconds())
}

结果:

hello world: 1, duraction : 201 ms 
hello world: 2, duraction : 201 ms 
hello world: 3, duraction : 201 ms 
hello world: 4, duraction : 201 ms 
hello world: 5, duraction : 201 ms 
hello world: 6, duraction : 200 ms 
hello world: 7, duraction : 201 ms 
hello world: 8, duraction : 201 ms 
hello world: 9, duraction : 201 ms 

这篇关于【Golang】定时任务Cron指南-毫秒级任务支持的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/693637

相关文章

Linux内核参数配置与验证详细指南

《Linux内核参数配置与验证详细指南》在Linux系统运维和性能优化中,内核参数(sysctl)的配置至关重要,本文主要来聊聊如何配置与验证这些Linux内核参数,希望对大家有一定的帮助... 目录1. 引言2. 内核参数的作用3. 如何设置内核参数3.1 临时设置(重启失效)3.2 永久设置(重启仍生效

Python列表去重的4种核心方法与实战指南详解

《Python列表去重的4种核心方法与实战指南详解》在Python开发中,处理列表数据时经常需要去除重复元素,本文将详细介绍4种最实用的列表去重方法,有需要的小伙伴可以根据自己的需要进行选择... 目录方法1:集合(set)去重法(最快速)方法2:顺序遍历法(保持顺序)方法3:副本删除法(原地修改)方法4:

python logging模块详解及其日志定时清理方式

《pythonlogging模块详解及其日志定时清理方式》:本文主要介绍pythonlogging模块详解及其日志定时清理方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录python logging模块及日志定时清理1.创建logger对象2.logging.basicCo

SpringQuartz定时任务核心组件JobDetail与Trigger配置

《SpringQuartz定时任务核心组件JobDetail与Trigger配置》Spring框架与Quartz调度器的集成提供了强大而灵活的定时任务解决方案,本文主要介绍了SpringQuartz定... 目录引言一、Spring Quartz基础架构1.1 核心组件概述1.2 Spring集成优势二、J

PyInstaller打包selenium-wire过程中常见问题和解决指南

《PyInstaller打包selenium-wire过程中常见问题和解决指南》常用的打包工具PyInstaller能将Python项目打包成单个可执行文件,但也会因为兼容性问题和路径管理而出现各种运... 目录前言1. 背景2. 可能遇到的问题概述3. PyInstaller 打包步骤及参数配置4. 依赖

java实现延迟/超时/定时问题

《java实现延迟/超时/定时问题》:本文主要介绍java实现延迟/超时/定时问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java实现延迟/超时/定时java 每间隔5秒执行一次,一共执行5次然后结束scheduleAtFixedRate 和 schedu

Redis实现延迟任务的三种方法详解

《Redis实现延迟任务的三种方法详解》延迟任务(DelayedTask)是指在未来的某个时间点,执行相应的任务,本文为大家整理了三种常见的实现方法,感兴趣的小伙伴可以参考一下... 目录1.前言2.Redis如何实现延迟任务3.代码实现3.1. 过期键通知事件实现3.2. 使用ZSet实现延迟任务3.3

golang获取当前时间、时间戳和时间字符串及它们之间的相互转换方法

《golang获取当前时间、时间戳和时间字符串及它们之间的相互转换方法》:本文主要介绍golang获取当前时间、时间戳和时间字符串及它们之间的相互转换,本文通过实例代码给大家介绍的非常详细,感兴趣... 目录1、获取当前时间2、获取当前时间戳3、获取当前时间的字符串格式4、它们之间的相互转化上篇文章给大家介

Nginx中配置HTTP/2协议的详细指南

《Nginx中配置HTTP/2协议的详细指南》HTTP/2是HTTP协议的下一代版本,旨在提高性能、减少延迟并优化现代网络环境中的通信效率,本文将为大家介绍Nginx配置HTTP/2协议想详细步骤,需... 目录一、HTTP/2 协议概述1.HTTP/22. HTTP/2 的核心特性3. HTTP/2 的优

Linux中的计划任务(crontab)使用方式

《Linux中的计划任务(crontab)使用方式》:本文主要介绍Linux中的计划任务(crontab)使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、前言1、linux的起源与发展2、什么是计划任务(crontab)二、crontab基础1、cro