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.

Best practices
Run scheduled jobs in Go with robfig/cron

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 with AddJob("0 * * * *", myJob{client: db}).
  • Prevent overlapping runs with cron.WithChain(cron.SkipIfStillRunning(cron.DefaultLogger)).
  • Set a schedule's zone with a CRON_TZ=Asia/Shanghai prefix, or configure the scheduler using cron.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.

Get a tailored plan

Contact us

Join the community

Scan with WeChat
to join the community

Try Guance

Start online and pay only for what you use.

Get started

Choose a Guance plan

Code hosting