Golang使用robfig/cron如何从指定epoch毫秒时间启动每秒定时任务
该需求完全可以实现。
默认使用@every 1s时任务对齐整秒触发,是因为内置固定间隔调度器的基准时间取的是任务注册时刻向上对齐整秒的值,不会保留毫秒级偏移,通过以下两种方案均可实现带固定毫秒偏移的每秒触发:
方案1:延迟注册任务(实现简单,无自定义逻辑)
核心逻辑:计算当前时间到首个目标偏移时间点的等待时长,到达时间点后注册周期任务,此时周期调度的基准时间会落在目标毫秒偏移点,后续每次间隔1s触发都会保持该偏移。如果需要注册后立刻触发首次任务,可在等待结束后先手动执行一次任务逻辑,再注册周期任务。
示例代码:
package main import ( "time" "github.com/robfig/cron/v3" ) func main() { c := cron.New() // 配置需要的毫秒偏移,示例为需求中的300ms targetOffsetMs := int64(300) now := time.Now() currentMs := now.UnixMilli() % 1000 // 计算距离首个目标触发点的等待时长 var waitDuration time.Duration if currentMs < targetOffsetMs { waitDuration = time.Duration(targetOffsetMs - currentMs) * time.Millisecond } else { waitDuration = time.Duration(1000 - currentMs + targetOffsetMs) * time.Millisecond } c.Start() // 等待到首个触发点 time.Sleep(waitDuration) // 如需首次任务立刻触发,打开下面这行注释 // go func() { /* 你的任务逻辑 */ }() // 注册周期任务,后续每次触发都会保持毫秒偏移 _, err := c.AddFunc("@every 1s", func() { // 你的任务逻辑 }) if err != nil { panic(err) } // 阻塞主进程,实际使用按场景替换 select {} }
注意:该方案在系统负载极高出现长调度延迟时,可能出现偏移漂移,对精度要求极高的场景推荐使用方案2
方案2:自定义Schedule实现(精度更高,无偏移漂移)
robfig/cron支持用户自定义调度规则,只要实现内置的Schedule接口即可。该方案直接在调度逻辑中固定毫秒偏移,就算运行中出现单次执行延迟,下一次触发也会自动对齐回目标偏移点,稳定性更高。
示例代码:
package main import ( "time" "github.com/robfig/cron/v3" ) // OffsetSecondSchedule 带固定毫秒偏移的每秒调度器 type OffsetSecondSchedule struct { offsetMs int64 // 毫秒偏移值,取值范围0-999 } // Next 实现Schedule接口,返回入参时间t之后的下一个触发时间 func (s OffsetSecondSchedule) Next(t time.Time) time.Time { currentMs := t.UnixMilli() % 1000 baseTime := t.Truncate(time.Second) if currentMs < s.offsetMs { // 当前毫秒小于目标偏移,触发点为当前整秒加偏移 return baseTime.Add(time.Duration(s.offsetMs) * time.Millisecond) } // 当前毫秒大于等于目标偏移,触发点为下一个整秒加偏移 return baseTime.Add(time.Second + time.Duration(s.offsetMs)*time.Millisecond) } func main() { c := cron.New() // 初始化自定义调度器,配置300ms偏移 schedule := OffsetSecondSchedule{offsetMs: 300} // 注册任务 c.Schedule(schedule, cron.FuncJob(func() { // 你的任务逻辑 })) c.Start() // 阻塞主进程,实际使用按场景替换 select {} }
补充说明
不要尝试通过标准cron表达式实现该需求,就算开启cron.WithSeconds()选项,cron表达式的最小支持粒度也仅到秒级,无法配置毫秒级偏移,必须通过上述两种方案实现。
内容的提问来源于stack exchange,提问作者Shavkatbek G'opporov
相关产品推荐
相关产品推荐

