robfig/cron (v3)
The standard choice. By default it parses 5-field Unix cron (no seconds) and also understands @every and @daily shortcuts:
import "github.com/robfig/cron/v3"
c := cron.New() // 5-field, server local time
// every weekday at 09:00 == 0 9 * * 1-5
c.AddFunc("0 9 * * 1-5", func() { report() })
c.AddFunc("@every 15m", func() { poll() })
c.Start()
select {} // block foreverNeed seconds or a timezone? Configure the parser:
loc, _ := time.LoadLocation("UTC")
c := cron.New(cron.WithSeconds(), cron.WithLocation(loc))
c.AddFunc("0 0 9 * * 1-5", report) // 6-field: sec min hour dom mon dowtime.Ticker (simple intervals)
If all you need is "every N", the standard library is enough — no dependency:
ticker := time.NewTicker(15 * time.Minute)
defer ticker.Stop()
for range ticker.C {
poll()
}Monitor it free with cron.watch
A goroutine that panics or a container that gets OOM-killed stops your schedule with no warning. A schedule is only a promise — cron.watch tells you if the job actually ran, alerts you when it silently fails, skips, or runs long, and keeps a history of every run.
import "net/http"
func report() {
defer http.Get("https://cron.watch/s/your-id") // ping after the run
doWork()
}