Golang中Cron定时任务调度不正确的问题探讨
Golang中Cron定时任务调度不正确的问题探讨 我的配置文件中包含以下4个Cron计划
CronProcess1 = "30 13 */15 * *" # 每15天在下午1:30执行
CronProcess1Reminder = "30 13 */3 * *" # 每3天在下午1:30执行
CronProcess2 = "30 13 */3 * *" # 每3天在下午1:30执行
CronProcess2Reminder = "30 13 */1 * *" # 每天在下午1:30执行
我使用以下代码初始化了一个新的Cron任务
c := cron.New(cron.WithLogger(adapters.GetCronLoggerAdapter()), cron.WithLocation(time.UTC))
查看日志,发现不同的进程似乎没有被正确调度
schedule [[now 2021-06-28 06:27:26.8877311 +0000 UTC entry 1 next 2021-07-01 13:30:00 +0000 UTC]]
schedule [[now 2021-06-28 06:27:26.8877311 +0000 UTC entry 2 next 2021-06-28 13:30:00 +0000 UTC]]
schedule [[now 2021-06-28 06:27:26.8877311 +0000 UTC entry 3 next 2021-06-28 13:30:00 +0000 UTC]]
schedule [[now 2021-06-28 06:27:26.8877311 +0000 UTC entry 4 next 2021-06-28 13:30:00 +0000 UTC]]
第一条记录的下次执行时间应该是2021-07-13 13:30:00。其他记录的时间也不正确。
有什么想法可能导致这个问题吗?
更多关于Golang中Cron定时任务调度不正确的问题探讨的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于Golang中Cron定时任务调度不正确的问题探讨的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
看来你的系统时区配置似乎有问题。
如果它与你的地理位置不匹配,那么任何基于时区的计算当然都会出错。
你所在的时区是哪个?你所在时区的早上6:30是否等同于UTC时间的下午1:30?
我认为这可能与我的时区设置有关。查看我的笔记本电脑,显示我处于 (UTC +3:00) 时区。 但通过谷歌查询我的时区,却显示为东部夏令时 (GMT-4)。
另外,重新运行了日志。现在是下午2点,但日志显示:
[[now 2021-06-29 11:02:04.9369524 +0000 UTC entry 1 next 2021-07-01 12:30:00 +0000 UTC]]
对应的是 30 12 */15 * *
问题出在Cron表达式的理解上。Go的cron库使用的是标准Unix cron格式,其中*/15在"天"字段中表示"每15天",但实际行为可能与你期望的不同。
标准cron的*/15在"天"字段中表示:在满足其他时间条件的情况下,在每月的第1、16、31天执行(如果月份有31天)。对于你的需求,应该使用更明确的表达式。
以下是修正后的代码示例:
package main
import (
"fmt"
"time"
"github.com/robfig/cron/v3"
)
func main() {
c := cron.New(cron.WithLocation(time.UTC))
// 每15天在下午1:30执行 - 使用明确的日期范围
// 方法1: 使用多个表达式
_, err1 := c.AddFunc("30 13 1,16 * *", func() {
fmt.Println("Process1 executed at", time.Now().UTC())
})
// 方法2: 如果需要更灵活的15天间隔,需要自定义调度器
_, err2 := c.AddFunc("30 13 */3 * *", func() {
fmt.Println("Process1Reminder executed at", time.Now().UTC())
})
_, err3 := c.AddFunc("30 13 */3 * *", func() {
fmt.Println("Process2 executed at", time.Now().UTC())
})
_, err4 := c.AddFunc("30 13 * * *", func() {
fmt.Println("Process2Reminder executed at", time.Now().UTC())
})
if err1 != nil || err2 != nil || err3 != nil4 != nil {
fmt.Println("Error adding cron jobs")
return
}
c.Start()
// 保持程序运行
select {}
}
对于真正的"每15天"调度(从特定日期开始),你需要自定义调度逻辑:
package main
import (
"fmt"
"time"
"github.com/robfig/cron/v3"
)
type CustomSchedule struct {
intervalDays int
startDate time.Time
hour int
minute int
}
func (cs *CustomSchedule) Next(t time.Time) time.Time {
// 计算从开始日期到当前时间的天数差
daysSinceStart := int(t.Sub(cs.startDate).Hours() / 24)
// 计算下一个执行日期
nextDays := ((daysSinceStart / cs.intervalDays) + 1) * cs.intervalDays
nextDate := cs.startDate.AddDate(0, 0, nextDays)
// 设置具体执行时间
nextTime := time.Date(
nextDate.Year(),
nextDate.Month(),
nextDate.Day(),
cs.hour,
cs.minute,
0, 0,
nextDate.Location(),
)
return nextTime
}
func main() {
c := cron.New(cron.WithLocation(time.UTC))
// 设置开始日期(例如从2021-06-01开始)
startDate := time.Date(2021, 6, 1, 0, 0, 0, 0, time.UTC)
// 每15天执行
customSchedule1 := &CustomSchedule{
intervalDays: 15,
startDate: startDate,
hour: 13,
minute: 30,
}
c.Schedule(customSchedule1, cron.FuncJob(func() {
fmt.Println("Process1 (every 15 days) executed at", time.Now().UTC())
}))
c.Start()
// 测试输出接下来几次执行时间
testTime := time.Date(2021, 6, 28, 6, 27, 26, 0, time.UTC)
for i := 0; i < 5; i++ {
nextTime := customSchedule1.Next(testTime)
fmt.Printf("Next execution %d: %v\n", i+1, nextTime)
testTime = nextTime
}
select {}
}
标准cron的*/n在"天"字段中的行为是:在满足月份有效天数的前提下,在1号、1+n、1+2n…号执行。对于"每3天"的需求,*/3会在一月的1、4、7…号执行,而不是从当前日期开始每3天执行。

