Add, remove, and inspect scheduled jobs in the cron scheduler.
// AddFunc adds a func to the Cron to be run on the given schedule.
// The spec is parsed using the time zone of this Cron instance as the default.
// An opaque ID is returned that can be used to later remove it.
// Returns an error if the spec cannot be parsed.
func (c *Cron) AddFunc(spec string, cmd func()) (EntryID, error)Parameters:
spec string - Cron specification string (e.g., "0 30 * * * *", "@hourly", "@every 5m")cmd func() - Function to execute on scheduleReturns:
EntryID - Unique identifier for the scheduled joberror - Error if spec is invalidUsage:
c := cron.New()
// Standard cron spec (5 fields: minute hour day month weekday)
id1, err := c.AddFunc("30 * * * *", func() {
fmt.Println("Every hour on the half hour")
})
if err != nil {
log.Fatal(err)
}
// Descriptor syntax
id2, _ := c.AddFunc("@hourly", func() {
fmt.Println("Every hour")
})
// Interval syntax
id3, _ := c.AddFunc("@every 1h30m", func() {
fmt.Println("Every 90 minutes")
})
// With timezone prefix
id4, _ := c.AddFunc("CRON_TZ=America/New_York 0 6 * * ?", func() {
fmt.Println("6am in New York")
})
c.Start()// AddJob adds a Job to the Cron to be run on the given schedule.
// The spec is parsed using the time zone of this Cron instance as the default.
// An opaque ID is returned that can be used to later remove it.
// Returns an error if the spec cannot be parsed.
func (c *Cron) AddJob(spec string, cmd Job) (EntryID, error)Type Definitions:
type Job interface {
Run()
}
type EntryID intUsage:
// Define a job type
type MyJob struct {
Name string
}
func (j MyJob) Run() {
fmt.Printf("Running job: %s\n", j.Name)
}
// Add the job
c := cron.New()
job := MyJob{Name: "DataProcessor"}
id, err := c.AddJob("@daily", job)
if err != nil {
log.Fatal(err)
}// Schedule adds a Job to the Cron to be run on the given schedule.
// The job is wrapped with the configured Chain.
// Returns the entry ID immediately.
func (c *Cron) Schedule(schedule Schedule, cmd Job) EntryIDType Definitions:
type Schedule interface {
// Next returns the next activation time, later than the given time
Next(time.Time) time.Time
}Usage:
// Parse schedule separately
schedule, err := cron.ParseStandard("0 0 * * *")
if err != nil {
log.Fatal(err)
}
// Define job
job := MyJob{Name: "Report"}
// Schedule it
c := cron.New()
id := c.Schedule(schedule, job)// Remove an entry from being run in the future.
// If the job is currently running, it will complete.
func (c *Cron) Remove(id EntryID)Usage:
c := cron.New()
// Add a job
id, _ := c.AddFunc("@every 5s", func() {
fmt.Println("Temporary job")
})
c.Start()
// Later: remove it
time.Sleep(30 * time.Second)
c.Remove(id)
fmt.Println("Job removed")// Entries returns a snapshot of the cron entries.
// The returned slice contains copies of entries, not references.
func (c *Cron) Entries() []EntryType Definitions:
type Entry struct {
// ID is the cron-assigned ID of this entry
ID EntryID
// Schedule on which this job should be run
Schedule Schedule
// Next time the job will run, or zero time if Cron hasn't started
// or this entry's schedule is unsatisfiable
Next time.Time
// Prev is the last time this job was run, or zero time if never
Prev time.Time
// WrappedJob is the thing to run when the Schedule is activated
WrappedJob Job
// Job is the original job submitted to cron
// Kept around so user code can access it later
Job Job
}
// Valid returns true if this is not the zero entry
func (e Entry) Valid() boolUsage:
c := cron.New()
c.AddFunc("@hourly", func() { fmt.Println("Job 1") })
c.AddFunc("@daily", func() { fmt.Println("Job 2") })
c.Start()
// Inspect all entries
entries := c.Entries()
for _, entry := range entries {
fmt.Printf("Job ID %d: Next run at %v, Last run at %v\n",
entry.ID, entry.Next, entry.Prev)
}// Entry returns a snapshot of the given entry, or nil if it couldn't be found.
// Returns a zero-value Entry if not found (check with Valid()).
func (c *Cron) Entry(id EntryID) EntryUsage:
c := cron.New()
id, _ := c.AddFunc("@hourly", func() { fmt.Println("Job") })
c.Start()
// Get specific entry
entry := c.Entry(id)
if entry.Valid() {
fmt.Printf("Next run: %v\n", entry.Next)
fmt.Printf("Previous run: %v\n", entry.Prev)
} else {
fmt.Println("Entry not found")
}// Location gets the time zone location.
// Returns the location used for interpreting schedules.
func (c *Cron) Location() *time.LocationUsage:
nyc, _ := time.LoadLocation("America/New_York")
c := cron.New(cron.WithLocation(nyc))
loc := c.Location()
fmt.Println("Scheduler timezone:", loc)The AddFunc method internally wraps functions using the FuncJob type. You can use this type directly if needed.
// FuncJob is a wrapper that turns a func() into a cron.Job
type FuncJob func()
// Run implements the Job interface
func (f FuncJob) Run()Usage:
// These are equivalent:
c.AddFunc("@hourly", func() { fmt.Println("Hello") })
// Or explicitly:
var job cron.FuncJob = func() { fmt.Println("Hello") }
c.AddJob("@hourly", job)package main
import (
"fmt"
"sync"
"time"
"github.com/robfig/cron/v3"
)
type JobManager struct {
cron *cron.Cron
jobs map[string]cron.EntryID
mu sync.Mutex
}
func NewJobManager() *JobManager {
return &JobManager{
cron: cron.New(),
jobs: make(map[string]cron.EntryID),
}
}
func (jm *JobManager) Start() {
jm.cron.Start()
}
func (jm *JobManager) Stop() {
jm.cron.Stop()
}
func (jm *JobManager) AddJob(name string, spec string, fn func()) error {
jm.mu.Lock()
defer jm.mu.Unlock()
// Remove existing job with same name if present
if id, exists := jm.jobs[name]; exists {
jm.cron.Remove(id)
}
// Add new job
id, err := jm.cron.AddFunc(spec, fn)
if err != nil {
return err
}
jm.jobs[name] = id
return nil
}
func (jm *JobManager) RemoveJob(name string) {
jm.mu.Lock()
defer jm.mu.Unlock()
if id, exists := jm.jobs[name]; exists {
jm.cron.Remove(id)
delete(jm.jobs, name)
}
}
func (jm *JobManager) ListJobs() []string {
jm.mu.Lock()
defer jm.mu.Unlock()
names := make([]string, 0, len(jm.jobs))
for name := range jm.jobs {
names = append(names, name)
}
return names
}
func main() {
jm := NewJobManager()
jm.Start()
// Add jobs dynamically
jm.AddJob("report", "@daily", func() {
fmt.Println("Running daily report")
})
jm.AddJob("backup", "@every 6h", func() {
fmt.Println("Running backup")
})
// List all jobs
fmt.Println("Active jobs:", jm.ListJobs())
// Update a job (replaces existing)
jm.AddJob("report", "@hourly", func() {
fmt.Println("Running hourly report (updated)")
})
// Remove a job
jm.RemoveJob("backup")
// Clean shutdown
defer jm.Stop()
select {}
}Next() method of their ScheduleIf a job is added while the scheduler is running, it's scheduled immediately based on the current time, not from when the scheduler started.