A Golang job scheduling library that lets you run Go functions at pre-determined intervals using cron expressions, fixed durations, daily, weekly, monthly, or one-time schedules with support for distributed deployments.
A Go job scheduling library that runs functions at pre-determined intervals using cron expressions, fixed durations, daily/weekly/monthly schedules, or one-time execution. Includes distributed deployment support.
Package: github.com/go-co-op/gocron/v2
Install: go get github.com/go-co-op/gocron/v2@v2.19.1
Min Go: 1.21.4
Import: import "github.com/go-co-op/gocron/v2"
s, err := gocron.NewScheduler()
if err != nil {
panic(err)
}
defer s.Shutdown()
// Add job
j, err := s.NewJob(
gocron.DurationJob(5*time.Second),
gocron.NewTask(func() {
fmt.Println("running")
}),
)
s.Start()
select {} // block// Fixed interval
gocron.DurationJob(5 * time.Minute)
// Cron expression
gocron.CronJob("*/5 * * * *", false)
// Daily at specific times
gocron.DailyJob(1, gocron.NewAtTimes(gocron.NewAtTime(9, 0, 0)))
// Task with parameters
gocron.NewTask(func(msg string, n int) {
fmt.Println(msg, n)
}, "hello", 42)
// Job options
s.NewJob(
gocron.DurationJob(time.Minute),
gocron.NewTask(myFunc),
gocron.WithName("my-job"),
gocron.WithTags("worker", "cleanup"),
gocron.WithSingletonMode(gocron.LimitModeReschedule),
)...every N seconds/minutes/hours → DurationJob for fixed intervals → DurationRandomJob for jittered intervals
...at specific times (9 AM, every Monday, etc.) → CronJob for cron expressions → DailyJob for daily schedules → WeeklyJob for weekly schedules → MonthlyJob for monthly schedules
...just once → OneTimeJob
→ Singleton Mode Guide — Prevent job from running with itself → Scheduler Limits Guide — Limit total concurrent jobs
→ Leader Election Guide — Simple, all-or-nothing → Distributed Locking Guide — Per-job locking
→ Logging Guide — Internal logging → Metrics Guide — Prometheus, StatsD integration → Lifecycle Monitoring Guide — Detailed events
The main orchestrator. Create with NewScheduler, add jobs, call Start(), clean up with Shutdown().
Quick reference: Creating Schedulers | Managing Jobs | Lifecycle
Defines when a job runs: duration-based, cron-based, time-based, or one-time.
Quick reference: Duration Jobs | Cron Jobs | Time-Based Jobs | One-Time Jobs
Defines what to run. Wrap any function with NewTask:
task := gocron.NewTask(func(ctx context.Context, msg string) {
fmt.Println(msg)
}, "hello")Context is auto-injected if first parameter is context.Context.
Quick reference: Tasks API
Configure how a job runs: identity, concurrency, lifecycle, events, distributed settings.
Quick reference: Identity Options | Concurrency Options | Timing Options | Event Options | Distributed Options
j, _ := s.NewJob(
gocron.DurationJob(30*time.Second),
gocron.NewTask(func() {
time.Sleep(time.Minute) // takes longer than interval
}),
gocron.WithSingletonMode(gocron.LimitModeReschedule),
)Learn more: Singleton Mode Guide
s, _ := gocron.NewScheduler(
gocron.WithStopTimeout(30*time.Second),
)
defer s.Shutdown()
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
defer cancel()
go func() {
<-ctx.Done()
if err := s.Shutdown(); err != nil {
log.Printf("Shutdown error: %v", err)
}
}()
s.Start()
select {} // block until shutdownLearn more: Graceful Shutdown Guide
// Leader election (simple)
s, _ := gocron.NewScheduler(
gocron.WithDistributedElector(myElector),
)
// OR distributed locking (per-job)
s, _ := gocron.NewScheduler(
gocron.WithDistributedLocker(myLocker),
)Learn more: Leader Election | Distributed Locking
j, _ := s.NewJob(
gocron.DurationJob(time.Minute),
gocron.NewTask(myFunc),
gocron.WithEventListeners(
gocron.BeforeJobRuns(func(jobID uuid.UUID, jobName string) {
log.Printf("Starting %s", jobName)
}),
gocron.AfterJobRunsWithError(func(jobID uuid.UUID, jobName string, err error) {
log.Printf("Failed %s: %v", jobName, err)
}),
),
)Learn more: Event Options
// Scheduler timezone
loc, _ := time.LoadLocation("America/Chicago")
s, _ := gocron.NewScheduler(gocron.WithLocation(loc))
// Per-job timezone (cron only)
j, _ := s.NewJob(
gocron.CronJob("TZ=America/New_York 0 9 * * *", false),
gocron.NewTask(doWork),
)Learn more: Time-Based Scheduling Guide
All errors are sentinel values; use errors.Is:
j, err := s.NewJob(
gocron.CronJob("invalid", false),
gocron.NewTask(myFunc),
)
if err != nil {
if errors.Is(err, gocron.ErrCronJobParse) {
// handle invalid cron
}
return err
}Complete reference: Errors
Complete API reference organized by category:
Task-oriented guides for common scenarios:
Getting Started
Jobs
Concurrency
Distributed
Observability
Advanced
Practical code examples organized by use case:
By Task
By Feature
By Scenario
Install with Tessl CLI
npx tessl i tessl/golang-github-com-go-co-op-gocron-v2@2.19.1