在Golang中特定的时期时间启动cronjob。

huangapple go评论85阅读模式
英文:

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)
}

后续:上述代码使用了传递给Nexttime.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
}

huangapple
  • 本文由 发表于 2022年7月14日 12:51:13
  • 转载请务必保留本文链接:https://go.coder-hub.com/72975345.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定