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?
CodePudding user response:
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
}