Run scheduled jobs in Go with robfig/cron
Use five-field or second-level cron schedules in Go, control overlapping runs, and handle panics explicitly.
Go's standard library does not parse cron expressions. The robfig/cron/v3 package provides an in-process scheduler: create it with cron.New(), register functions with AddFunc(), and call Start().
Scheduling depends on the process staying alive and having enough resources. This is not a durable job queue or a real-time execution guarantee.
Install the package
From your Go module:
go get github.com/robfig/cron/v3
Run a function every minute
package main
import (
"fmt"
"log"
"github.com/robfig/cron/v3"
)
func main() {
c := cron.New()
_, err := c.AddFunc("* * * * *", func() {
fmt.Println("Hello world!")
})
if err != nil {
log.Fatal(err)
}
c.Start()
select {}
}
The default expression has five fields: minute, hour, day of month, month, and day of week. For example, 30 3 * * * runs daily at 03:30 in the configured time zone. In an application, replace the indefinite block with your normal process lifecycle and shutdown handling.
Include seconds
Version 3 requires an explicit option for six-field expressions:
c := cron.New(cron.WithSeconds())
_, err := c.AddFunc("*/10 * * * * *", func() {
fmt.Println("Every 10 seconds")
})
if err != nil {
log.Fatal(err)
}
This is a registration fragment; start and retain the scheduler as in the complete example.
Useful scheduling options
- Use descriptors such as
@every 5m,@daily, and@hourly. - For a task with dependencies, implement
Run()and register it withAddJob("0 * * * *", myJob{client: db}). - Prevent overlapping runs with
cron.WithChain(cron.SkipIfStillRunning(cron.DefaultLogger)). - Set a schedule's zone with a
CRON_TZ=Asia/Shanghaiprefix, or configure the scheduler usingcron.WithLocation(loc). - Record the task name, start time, outcome, and duration. In-process jobs do not automatically appear in the system cron log. After collecting completion logs in Guance, configure a log detection rule for the expected completion window. Investigate missing execution and missing log collection separately.
Use a ticker for simple intervals
When calendar times are unnecessary, the standard library is enough:
ticker := time.NewTicker(5 * time.Minute)
defer ticker.Stop()
for range ticker.C {
doWork()
}
A ticker expresses an interval, not “every day at 02:00.” Slow consumers can also cause ticks to be adjusted or dropped.
FAQ
Are missed runs replayed after a restart?
No. robfig/cron keeps its schedules in memory. For durable execution, use a scheduler or queue with explicitly configured persistence and recovery behavior. System cron can run outside the application, but ordinary cron does not itself replay every run missed while the host was down.
Does version 3 recover panics automatically?
No. Opt in with cron.WithChain(cron.Recover(cron.DefaultLogger)). An unrecovered panic in a job can terminate the process. Recovery prevents that panic from propagating, but your task still needs error reporting and consistent business state.
Can I add or remove jobs while it runs?
Yes. Check the error returned by AddFunc(), retain its EntryID, and call Remove(id) to remove the entry. Entries() lists the registered schedules.
The version 3 documentation explains the parser and panic-handling changes.
Contact us
Join the community
to join the community
Try Guance
Start online and pay only for what you use.
Get startedChoose a Guance plan