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

quick-start.mddocs/guides/getting-started/

Quick Start Guide

Get started with gocron v2 in minutes. This guide walks you through creating your first scheduled job.

Installation

go get github.com/go-co-op/gocron/v2

Your First Job

Basic Example

package main

import (
    "fmt"
    "time"

    "github.com/go-co-op/gocron/v2"
)

func main() {
    // Create a new scheduler
    s, err := gocron.NewScheduler()
    if err != nil {
        panic(err)
    }
    defer s.Shutdown()

    // Add a job that runs every minute
    j, err := s.NewJob(
        gocron.DurationJob(time.Minute),
        gocron.NewTask(func() {
            fmt.Println("Job running at", time.Now())
        }),
    )
    if err != nil {
        panic(err)
    }

    fmt.Println("Job scheduled with ID:", j.ID())

    // Start the scheduler
    s.Start()

    // Block forever (or until signal)
    select {}
}

Output:

Job scheduled with ID: 550e8400-e29b-41d4-a716-446655440000
Job running at 2024-01-15 14:30:00
Job running at 2024-01-15 14:31:00
Job running at 2024-01-15 14:32:00
...

Scheduler Lifecycle

Create

func NewScheduler(options ...SchedulerOption) (Scheduler, error)

Creates a new scheduler instance:

s, err := gocron.NewScheduler()
if err != nil {
    log.Fatal(err)
}

Start

s.Start()

Starts executing jobs in the background. This is non-blocking.

Shutdown

defer s.Shutdown()

Always use defer to ensure graceful cleanup when your program exits.

Creating Jobs

Duration-Based Jobs

Run every N duration:

// Every 5 seconds
j, _ := s.NewJob(
    gocron.DurationJob(5*time.Second),
    gocron.NewTask(myFunc),
)

// Every 10 minutes
j, _ = s.NewJob(
    gocron.DurationJob(10*time.Minute),
    gocron.NewTask(myFunc),
)

// Every hour
j, _ = s.NewJob(
    gocron.DurationJob(time.Hour),
    gocron.NewTask(myFunc),
)

Cron Jobs

Use cron expressions for time-based schedules:

// Every day at 9 AM (cron format)
j, _ := s.NewJob(
    gocron.CronJob("0 9 * * *", false),
    gocron.NewTask(myFunc),
)

// Every Monday at 2 PM
j, _ = s.NewJob(
    gocron.CronJob("0 14 * * 1", false),
    gocron.NewTask(myFunc),
)

Cron format: minute hour day month weekday

  • * = any value
  • 0 9 * * * = 9:00 AM every day
  • 0 14 * * 1 = 2:00 PM every Monday

Daily Jobs

Run at specific times each day:

// Every day at 9 AM
j, _ := s.NewJob(
    gocron.DailyJob(
        1,
        gocron.NewAtTimes(gocron.NewAtTime(9, 0, 0)),
    ),
    gocron.NewTask(myFunc),
)

See Advanced: Time-Based Scheduling for WeeklyJob, MonthlyJob, and OneTimeJob.

Task Functions

Simple Function

task := gocron.NewTask(func() {
    fmt.Println("Hello from job!")
})

Function with Parameters

task := gocron.NewTask(
    func(name string, count int) {
        fmt.Printf("Hello %s, count: %d\n", name, count)
    },
    "Alice",
    42,
)

Parameters are passed after the function.

Function with Context

If the first parameter is context.Context, gocron injects it:

task := gocron.NewTask(func(ctx context.Context) {
    select {
    case <-ctx.Done():
        fmt.Println("Job cancelled")
        return
    default:
        doWork()
    }
})

Context is cancelled when:

  • Scheduler shuts down
  • Job is removed
  • Job stop time is reached

Common Options

Job Name

j, _ := s.NewJob(
    gocron.DurationJob(time.Minute),
    gocron.NewTask(myFunc),
    gocron.WithName("my-cleanup-job"),
)

Names make jobs easier to identify in logs and metrics.

Tags

j, _ := s.NewJob(
    gocron.DurationJob(time.Minute),
    gocron.NewTask(myFunc),
    gocron.WithTags("cleanup", "database"),
)

Use tags to group and manage related jobs.

Start Immediately

Run once immediately, then follow normal schedule:

j, _ := s.NewJob(
    gocron.DurationJob(time.Minute),
    gocron.NewTask(myFunc),
    gocron.WithStartAt(gocron.WithStartImmediately()),
)

Complete Example

package main

import (
    "fmt"
    "log"
    "os"
    "os/signal"
    "syscall"
    "time"

    "github.com/go-co-op/gocron/v2"
)

func main() {
    // Create scheduler
    s, err := gocron.NewScheduler()
    if err != nil {
        log.Fatal(err)
    }
    defer func() {
        if err := s.Shutdown(); err != nil {
            log.Printf("Shutdown error: %v", err)
        }
    }()

    // Add cleanup job (every 5 minutes)
    _, err = s.NewJob(
        gocron.DurationJob(5*time.Minute),
        gocron.NewTask(cleanupOldFiles),
        gocron.WithName("cleanup-files"),
        gocron.WithTags("maintenance"),
    )
    if err != nil {
        log.Fatal(err)
    }

    // Add report job (daily at 9 AM)
    _, err = s.NewJob(
        gocron.DailyJob(
            1,
            gocron.NewAtTimes(gocron.NewAtTime(9, 0, 0)),
        ),
        gocron.NewTask(generateDailyReport),
        gocron.WithName("daily-report"),
        gocron.WithTags("reporting"),
    )
    if err != nil {
        log.Fatal(err)
    }

    // Start scheduler
    s.Start()
    fmt.Println("Scheduler started. Press Ctrl+C to exit.")

    // Wait for interrupt signal
    sigCh := make(chan os.Signal, 1)
    signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
    <-sigCh

    fmt.Println("\nShutting down gracefully...")
}

func cleanupOldFiles() {
    fmt.Println("Cleaning up old files...")
    // Your cleanup logic here
}

func generateDailyReport() {
    fmt.Println("Generating daily report...")
    // Your report logic here
}

Next Steps

Now that you have a working scheduler, explore these topics:

Troubleshooting

Jobs Not Running

Problem: Jobs are created but not executing.

Solution: Make sure you called s.Start():

s.Start() // Don't forget this!
select {}

Program Exits Immediately

Problem: Program exits before jobs run.

Solution: Add a blocking statement:

s.Start()
select {} // Block forever

Or wait for a signal:

s.Start()
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
<-sigCh

Shutdown Errors

Problem: Errors during shutdown.

Solution: Always use defer and check errors:

defer func() {
    if err := s.Shutdown(); err != nil {
        log.Printf("Shutdown error: %v", err)
    }
}()

Related Documentation

Install with Tessl CLI

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

docs

index.md

tile.json