Home > Blockchain >  Start cronjob at specific epoch time in golang
Start cronjob at specific epoch time in golang

Time:07-14

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
}
  • Related