Goで特定の時間にタスクを実行できる関数を実装する方法の例を探していましたが、何も見つかりませんでした。
私は自分で実装し、それを回答で共有しているので、他の人が自分の実装のリファレンスを持つことができます。
これは一般的な実装であり、以下を設定できます。
更新:(メモリリークが修正されました)
import (
"fmt"
"time"
)
const INTERVAL_PERIOD time.Duration = 24 * time.Hour
const HOUR_TO_TICK int = 23
const MINUTE_TO_TICK int = 00
const SECOND_TO_TICK int = 03
type jobTicker struct {
timer *time.Timer
}
func runningRoutine() {
jobTicker := &jobTicker{}
jobTicker.updateTimer()
for {
<-jobTicker.timer.C
fmt.Println(time.Now(), "- just ticked")
jobTicker.updateTimer()
}
}
func (t *jobTicker) updateTimer() {
nextTick := time.Date(time.Now().Year(), time.Now().Month(),
time.Now().Day(), HOUR_TO_TICK, MINUTE_TO_TICK, SECOND_TO_TICK, 0, time.Local)
if !nextTick.After(time.Now()) {
nextTick = nextTick.Add(INTERVAL_PERIOD)
}
fmt.Println(nextTick, "- next tick")
diff := nextTick.Sub(time.Now())
if t.timer == nil {
t.timer = time.NewTimer(diff)
} else {
t.timer.Reset(diff)
}
}
@Calebが言うように、@ Daniele Bが提供する答えは十分ではありません。新しいティッカーを作成するたびに古いティッカーが解放されることはないため、実装はメモリをリークします。
だから私はtime.timer
、そしてそれを毎回リセットします、ここの例:
package main
import (
"fmt"
"time"
)
const INTERVAL_PERIOD time.Duration = 24 * time.Hour
const HOUR_TO_TICK int = 23
const MINUTE_TO_TICK int = 21
const SECOND_TO_TICK int = 03
type jobTicker struct {
t *time.Timer
}
func getNextTickDuration() time.Duration {
now := time.Now()
nextTick := time.Date(now.Year(), now.Month(), now.Day(), HOUR_TO_TICK, MINUTE_TO_TICK, SECOND_TO_TICK, 0, time.Local)
if nextTick.Before(now) {
nextTick = nextTick.Add(INTERVAL_PERIOD)
}
return nextTick.Sub(time.Now())
}
func NewJobTicker() jobTicker {
fmt.Println("new tick here")
return jobTicker{time.NewTimer(getNextTickDuration())}
}
func (jt jobTicker) updateJobTicker() {
fmt.Println("next tick here")
jt.t.Reset(getNextTickDuration())
}
func main() {
jt := NewJobTicker()
for {
<-jt.t.C
fmt.Println(time.Now(), "- just ticked")
jt.updateJobTicker()
}
}
誰かがこの質問に立ち寄った場合、簡単な解決策を探しています。ジョブのスケジュールを本当に簡単にするきちんとしたライブラリを見つけました。
リンク: https://github.com/jasonlvhit/gocron
APIは非常に単純です。
import (
"fmt"
"github.com/jasonlvhit/gocron"
)
func task() {
fmt.Println("Task is being performed.")
}
func main() {
s := gocron.NewScheduler()
s.Every(2).Hours().Do(task)
<- s.Start()
}
慣れていれば、実際にcrontab構文をサポートするパッケージを作成しました。次に例を示します。
ctab := crontab.New()
ctab.AddJob("*/5 * * * *", myFunc)
ctab.AddJob("0 0 * * *", myFunc2)
パッケージリンク: https://github.com/mileusna/crontab
これは、サードパーティのライブラリを必要としない、もう1つの一般的な実装です。
1日1回正午にfunc
を実行します。
time.Hour * 24
time.Hour * 12
1日2回03:40(00:00 + 03:40)および15:40(12:00 + 03:40)にfunc
を実行します。
time.Hour * 12
time.Hour * 3 + time.Minute * 40
変更:
context.Context
はキャンセルに使用でき、テスト可能にします。time.Ticker
は、次の実行時間を計算する必要をなくします。package main
import (
"context"
"time"
)
// Schedule calls function `f` with a period `p` offsetted by `o`.
func Schedule(ctx context.Context, p time.Duration, o time.Duration, f func(time.Time)) {
// Position the first execution
first := time.Now().Truncate(p).Add(o)
if first.Before(time.Now()) {
first = first.Add(p)
}
firstC := time.After(first.Sub(time.Now()))
// Receiving from a nil channel blocks forever
t := &time.Ticker{C: nil}
for {
select {
case v := <-firstC:
// The ticker has to be started before f as it can take some time to finish
t = time.NewTicker(p)
f(v)
case v := <-t.C:
f(v)
case <-ctx.Done():
t.Stop()
return
}
}
}
package main
import (
"time"
)
// Repeat calls function `f` with a period `d` offsetted by `o`.
func Repeat(d time.Duration, o time.Duration, f func(time.Time)) {
next := time.Now().Truncate(d).Add(o)
if next.Before(time.Now()) {
next = next.Add(d)
}
t := time.NewTimer(next.Sub(time.Now()))
for {
v := <-t.C
next = next.Add(d)
t.Reset(next.Sub(time.Now()))
f(v)
}
}