Golang: реализация cron / выполнение задач в определенное время

Я искал примеры того, как реализовать функцию, которая позволяет выполнять задачи в определенное время в Go, но я ничего не мог найти.

я реализовал один сам, и я делюсь им в ответах, поэтому другие люди могут иметь ссылку для своей собственной реализации.

5 ответов


это общая реализация, которая позволяет установить:

  • интервала
  • час в ТИК
  • минут в ТИК
  • второй ТИК

обновление: (утечка памяти была исправлена)

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

ответ, предоставленный @Daniele B, недостаточно хорош, поскольку @Caleb говорит, что реализация утечки памяти, потому что каждый раз, когда мы создаем новый тикер, старый никогда не будет выпущен.

поэтому я заворачиваю 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


код очень запутан для чтения, немного сложно понять, какие из них являются переменными времени, а какие-переменными тикера.

Я думаю, что это более или менее делает правильную вещь, выяснить, как долго между сейчас и следующий "ТИК" и спать до этого тика.

было бы более поучительно использовать

func AfterFunc

func AfterFunc(d Duration, f func()) *Timer
AfterFunc waits for the duration to elapse and then calls f in its own   goroutine. It returns a Timer that can be used to cancel the call using its Stop   method.

Это приблизилось бы к тому, что вы пытаетесь дублировать, и чувствует себя более похожим на меня.