英文:
Start cronjob at specific epoch time in golang
问题
我正在使用 github.com/robfig/cron 库。我想要在以毫秒为单位的 epoch 时间上运行 cron 作业,并且每秒钟执行一次。cron 在每秒的第 000
毫秒开始。我需要它在特定的时间开始运行。
例如,如果我使用以下代码:
c := cron.New()
c.AddFunc("@every 1s", func() {
// 做一些事情
})
c.Start()
并在 1657713890300
的 epoch 时间戳上运行它,那么我希望该函数在以下时间运行:
1657713891300
1657713892300
1657713893300
。
目前,cron 在以下时间运行:
1657713891000
1657713892000
1657713893000
。
这种情况是否可行?
英文:
I am using github.com/robfig/cron library. I want to run cronjob at epoc time with millisecond and work every second. The cron starts at 000
millisecond. I need it to start at specific times.
For example if I take the following:
c := cron.New()
c.AddFunc("@every 1s", func() {
// Do Something
})
c.Start()
And run it at 1657713890300
epoc timestamp then I want the function to run at:
1657713891300
1657713892300
1657713893300
.
Currently, cron running at
1657713891000
1657713892000
1657713893000
.
Is this possible?
答案1
得分: 0
当你使用@every 1s
时,库会创建一个ConstantDelaySchedule
,它会“四舍五入,使下一次激活时间在整秒上”。
如果这不是你想要的,你可以创建自己的调度器(playground):
package main
import (
"fmt"
"time"
"github.com/robfig/cron/v3"
)
func main() {
time.Sleep(300 * time.Millisecond) // 为了不在接近整秒的边界启动cron
c := cron.New()
c.Schedule(CustomConstantDelaySchedule{time.Second}, cron.FuncJob(func() {
fmt.Println(time.Now().UnixNano())
}))
c.Start()
time.Sleep(time.Second * 5)
}
// CustomConstantDelaySchedule是库中ConstantDelaySchedule的副本,去除了四舍五入
type CustomConstantDelaySchedule struct {
Delay time.Duration
}
// Next返回下一次运行的时间
func (schedule CustomConstantDelaySchedule) Next(t time.Time) time.Time {
return t.Add(schedule.Delay)
}
后续:上述代码使用了传递给Next
的time.Time
,即time.Now()
,所以时间会随着时间的推移而慢慢增加。
可以解决这个问题(参见下面的代码 - playground),但这样做会引入一些潜在的问题(CustomConstantDelaySchedule
不能被重用,如果作业运行时间过长,仍然会出现差异)。我建议你考虑放弃使用cron包,而直接使用time.Ticker
。
package main
import (
"fmt"
"time"
"github.com/robfig/cron/v3"
)
func main() {
time.Sleep(300 * time.Millisecond) // 为了不在接近整秒的边界启动cron
c := cron.New()
c.Schedule(CustomConstantDelaySchedule{Delay: time.Second}, cron.FuncJob(func() {
fmt.Println(time.Now().UnixNano())
}))
c.Start()
time.Sleep(time.Second * 5)
}
// CustomConstantDelaySchedule是库中ConstantDelaySchedule的副本,去除了四舍五入
// 注意,由于这个结构体存储了上次的时间,它不能被重用!
type CustomConstantDelaySchedule struct {
Delay time.Duration
lastTarget time.Time
}
// Next返回下一次运行的时间
func (schedule CustomConstantDelaySchedule) Next(t time.Time) time.Time {
if schedule.lastTarget.IsZero() {
schedule.lastTarget = t.Add(schedule.Delay)
} else {
schedule.lastTarget = schedule.lastTarget.Add(schedule.Delay)
}
return schedule.lastTarget
}
英文:
When you use @every 1s
the library creates a ConstantDelaySchedule
which "rounds so that the next activation time will be on the second".
If that is not what you want then you can create your own scheduler (playground):
package main
import (
"fmt"
"time"
"github.com/robfig/cron/v3"
)
func main() {
time.Sleep(300 * time.Millisecond) // So we don't start cron too near the second boundary
c := cron.New()
c.Schedule(CustomConstantDelaySchedule{time.Second}, cron.FuncJob(func() {
fmt.Println(time.Now().UnixNano())
}))
c.Start()
time.Sleep(time.Second * 5)
}
// CustomConstantDelaySchedule is a copy of the libraries ConstantDelaySchedule with the rounding removed
type CustomConstantDelaySchedule struct {
Delay time.Duration
}
// Next returns the next time this should be run.
func (schedule CustomConstantDelaySchedule) Next(t time.Time) time.Time {
return t.Add(schedule.Delay)
}
Follow up: The above uses the time.Time
passed to Next
which is time.Now()
so will the time will slowly advance over time.
Addressing this is possible (see below - playground) but doing this introduces some potential issuers (the CustomConstantDelaySchedule
must not be reused and if the jobs take too long to run then you will still end up with discrepancies). I'd suggest that you consider moving away from the cron package and just use a time.Ticker
.
package main
import (
"fmt"
"time"
"github.com/robfig/cron/v3"
)
func main() {
time.Sleep(300 * time.Millisecond) // So we don't start cron too nead the second boundary
c := cron.New()
c.Schedule(CustomConstantDelaySchedule{Delay: time.Second}, cron.FuncJob(func() {
fmt.Println(time.Now().UnixNano())
}))
c.Start()
time.Sleep(time.Second * 5)
}
// CustomConstantDelaySchedule is a copy of the libraries ConstantDelaySchedule with the rounding removed
// Note that because this stored the last time it cannot be reused!
type CustomConstantDelaySchedule struct {
Delay time.Duration
lastTarget time.Time
}
// Next returns the next time this should be run.
func (schedule CustomConstantDelaySchedule) Next(t time.Time) time.Time {
if schedule.lastTarget.IsZero() {
schedule.lastTarget = t.Add(schedule.Delay)
} else {
schedule.lastTarget = schedule.lastTarget.Add(schedule.Delay)
}
return schedule.lastTarget
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论