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.
Practical lifecycle management examples.
package main
import (
"fmt"
"time"
"github.com/go-co-op/gocron/v2"
"github.com/google/uuid"
)
func main() {
s, _ := gocron.NewScheduler()
defer s.Shutdown()
j, _ := s.NewJob(
gocron.DurationJob(time.Minute),
gocron.NewTask(func() error {
fmt.Println("Doing work...")
time.Sleep(time.Second)
// Simulate occasional failure
if time.Now().Unix()%3 == 0 {
return fmt.Errorf("simulated error")
}
return nil
}),
gocron.WithName("monitored-job"),
gocron.WithEventListeners(
gocron.BeforeJobRuns(func(jobID uuid.UUID, jobName string) {
fmt.Printf("[%v] Starting: %s\n", time.Now().Format(time.RFC3339), jobName)
}),
gocron.AfterJobRuns(func(jobID uuid.UUID, jobName string) {
fmt.Printf("[%v] Completed: %s\n", time.Now().Format(time.RFC3339), jobName)
}),
gocron.AfterJobRunsWithError(func(jobID uuid.UUID, jobName string, err error) {
fmt.Printf("[%v] Failed: %s - %v\n", time.Now().Format(time.RFC3339), jobName, err)
// Send alert, log to monitoring system, etc.
}),
),
)
s.Start()
select {}
}import (
"context"
"os"
"os/signal"
"syscall"
)
func main() {
s, _ := gocron.NewScheduler(
gocron.WithStopTimeout(30*time.Second),
)
s.NewJob(
gocron.DurationJob(time.Minute),
gocron.NewTask(func(ctx context.Context) {
fmt.Println("Long-running task started")
for i := 0; i < 60; i++ {
select {
case <-ctx.Done():
fmt.Println("Task cancelled, cleaning up...")
cleanup()
return
default:
time.Sleep(time.Second)
fmt.Printf("Progress: %d/60\n", i+1)
}
}
fmt.Println("Task completed")
}),
gocron.WithName("long-task"),
)
s.Start()
// Wait for interrupt
ctx, cancel := signal.NotifyContext(
context.Background(),
os.Interrupt,
syscall.SIGTERM,
)
defer cancel()
<-ctx.Done()
fmt.Println("Received shutdown signal, stopping scheduler...")
if err := s.Shutdown(); err != nil {
fmt.Printf("Shutdown error: %v\n", err)
}
fmt.Println("Shutdown complete")
}
func cleanup() {
fmt.Println("Cleaning up resources...")
}type jobTracker struct {
jobs map[uuid.UUID]*jobInfo
mu sync.Mutex
}
type jobInfo struct {
Name string
LastRun time.Time
LastStatus string
RunCount int
}
func newJobTracker() *jobTracker {
return &jobTracker{
jobs: make(map[uuid.UUID]*jobInfo),
}
}
func (t *jobTracker) JobScheduled(jobID uuid.UUID, job gocron.Job) {
t.mu.Lock()
defer t.mu.Unlock()
t.jobs[jobID] = &jobInfo{
Name: job.Name(),
LastStatus: "scheduled",
}
}
func (t *jobTracker) JobStarted(jobID uuid.UUID, job gocron.Job) {
t.mu.Lock()
defer t.mu.Unlock()
if info, ok := t.jobs[jobID]; ok {
info.LastStatus = "running"
info.LastRun = time.Now()
}
}
func (t *jobTracker) JobCompleted(jobID uuid.UUID, job gocron.Job, err error) {
t.mu.Lock()
defer t.mu.Unlock()
if info, ok := t.jobs[jobID]; ok {
info.RunCount++
if err != nil {
info.LastStatus = "failed"
} else {
info.LastStatus = "completed"
}
}
}
func (t *jobTracker) JobUnscheduled(jobID uuid.UUID, job gocron.Job) {
t.mu.Lock()
defer t.mu.Unlock()
delete(t.jobs, jobID)
}
func (t *jobTracker) ConcurrencyLimitReached(limitType string, job gocron.Job) {}
func (t *jobTracker) PrintStatus() {
t.mu.Lock()
defer t.mu.Unlock()
fmt.Println("\n=== Job Status ===")
for jobID, info := range t.jobs {
fmt.Printf("%s: %s (runs: %d, last: %v)\n",
info.Name, info.LastStatus, info.RunCount, info.LastRun)
}
fmt.Println()
}
func main() {
tracker := newJobTracker()
s, _ := gocron.NewScheduler(
gocron.WithSchedulerMonitor(tracker),
)
defer s.Shutdown()
s.NewJob(
gocron.DurationJob(5*time.Second),
gocron.NewTask(func() {
time.Sleep(time.Second)
}),
gocron.WithName("worker-1"),
)
s.NewJob(
gocron.DurationJob(10*time.Second),
gocron.NewTask(func() error {
if time.Now().Unix()%2 == 0 {
return fmt.Errorf("error")
}
return nil
}),
gocron.WithName("worker-2"),
)
s.Start()
// Print status every 15 seconds
ticker := time.NewTicker(15 * time.Second)
defer ticker.Stop()
go func() {
for range ticker.C {
tracker.PrintStatus()
}
}()
time.Sleep(time.Minute)
}func main() {
s, _ := gocron.NewScheduler()
defer s.Shutdown()
// Run initialization immediately
initJob, _ := s.NewJob(
gocron.OneTimeJob(
gocron.OneTimeJobStartDateTime(time.Now()),
),
gocron.NewTask(func() {
fmt.Println("Initializing system...")
time.Sleep(2 * time.Second)
fmt.Println("Initialization complete")
}),
gocron.WithName("init"),
)
// Regular jobs start after init
s.NewJob(
gocron.DurationJob(time.Minute),
gocron.NewTask(func() {
fmt.Println("Regular task running")
}),
gocron.WithName("regular-task"),
)
s.Start()
// Wait for initialization
time.Sleep(3 * time.Second)
fmt.Println("All systems ready")
select {}
}Install with Tessl CLI
npx tessl i tessl/golang-github-com-go-co-op-gocron-v2@2.19.1docs
api
examples
guides