CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/golang-github-com-go-co-op-gocron-v2

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.

Overview
Eval results
Files

index.mddocs/

gocron v2

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"

Quick Start

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

Common Patterns

// 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),
)

Decision Guides

I need to schedule a job...

...every N seconds/minutes/hoursDurationJob 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 onceOneTimeJob

I need to prevent concurrent executions

Singleton Mode Guide — Prevent job from running with itself → Scheduler Limits Guide — Limit total concurrent jobs

I need to deploy across multiple instances

Leader Election Guide — Simple, all-or-nothing → Distributed Locking Guide — Per-job locking

I need observability

Logging Guide — Internal logging → Metrics Guide — Prometheus, StatsD integration → Lifecycle Monitoring Guide — Detailed events

Core Concepts

Scheduler

The main orchestrator. Create with NewScheduler, add jobs, call Start(), clean up with Shutdown().

Quick reference: Creating Schedulers | Managing Jobs | Lifecycle

Job Definition

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

Task

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

Job Options

Configure how a job runs: identity, concurrency, lifecycle, events, distributed settings.

Quick reference: Identity Options | Concurrency Options | Timing Options | Event Options | Distributed Options

Essential Patterns

Prevent Overlapping Runs

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

Graceful Shutdown

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 shutdown

Learn more: Graceful Shutdown Guide

Distributed Deployment

// 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

Event Handling

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

Timezone-Aware Scheduling

// 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

Error Handling

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

Documentation Organization

Quick References

API Documentation

Complete API reference organized by category:

Guides

Task-oriented guides for common scenarios:

Getting Started

Jobs

Concurrency

Distributed

Observability

Advanced

Examples

Practical code examples organized by use case:

By Task

By Feature

By Scenario

Next Steps

Install with Tessl CLI

npx tessl i tessl/golang-github-com-go-co-op-gocron-v2

docs

index.md

tile.json