英文:
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 时间戳上运行它,那么我希望该函数在以下时间运行:
165771389130016577138923001657713893300。
目前,cron 在以下时间运行:
165771389100016577138920001657713893000。
这种情况是否可行?
英文:
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:
165771389130016577138923001657713893300.
Currently, cron running at
165771389100016577138920001657713893000.
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
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论