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.
Schedule jobs to run once, either immediately or at specific times.
j, _ := s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartImmediately()),
gocron.NewTask(doInitialization),
)
// Runs once when scheduler starts, then removed// Warm up caches or load configuration
j, _ := s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartImmediately()),
gocron.NewTask(func() {
fmt.Println("Loading configuration...")
loadConfig()
fmt.Println("Warming up caches...")
warmupCaches()
fmt.Println("Initialization complete")
}),
gocron.WithName("init"),
)// Run migration once on startup
j, _ := s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartImmediately()),
gocron.NewTask(func() error {
fmt.Println("Running database migrations...")
if err := runMigrations(); err != nil {
return fmt.Errorf("migration failed: %w", err)
}
fmt.Println("Migrations complete")
return nil
}),
gocron.WithName("db-migration"),
)// Run in 1 hour
futureTime := time.Now().Add(time.Hour)
j, _ := s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartDateTime(futureTime)),
gocron.NewTask(doDelayedTask),
)// Send reminder in 24 hours
reminderTime := time.Now().Add(24 * time.Hour)
j, _ := s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartDateTime(reminderTime)),
gocron.NewTask(func(email string) {
sendReminder(email)
}, user.Email),
)// Christmas morning notification
christmasDate := time.Date(2024, 12, 25, 9, 0, 0, 0, time.Local)
j, _ := s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartDateTime(christmasDate)),
gocron.NewTask(sendHolidayGreeting),
)// Schedule account expiration
trialEnd := user.TrialStartDate.Add(14 * 24 * time.Hour)
j, _ := s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartDateTime(trialEnd)),
gocron.NewTask(func(userID string) {
fmt.Printf("Trial expired for user %s\n", userID)
expireTrialAccount(userID)
sendTrialExpiredEmail(userID)
}, user.ID),
gocron.WithName(fmt.Sprintf("trial-expiry-%s", user.ID)),
)j, _ := s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartDateTimes(
time.Now().Add(1*time.Hour),
time.Now().Add(2*time.Hour),
time.Now().Add(3*time.Hour),
)),
gocron.NewTask(doScheduledTask),
)
// Runs 3 times, then removedj, _ := s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartDateTimes(
time.Date(2024, 12, 24, 9, 0, 0, 0, time.Local), // Christmas Eve
time.Date(2024, 12, 25, 9, 0, 0, 0, time.Local), // Christmas Day
time.Date(2024, 12, 31, 23, 0, 0, 0, time.Local), // New Year's Eve
)),
gocron.NewTask(sendHolidayGreeting),
)// Send reminders 7 days, 3 days, and 1 day before event
eventDate := time.Date(2024, 12, 31, 18, 0, 0, 0, time.Local)
j, _ := s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartDateTimes(
eventDate.Add(-7*24*time.Hour), // 7 days before
eventDate.Add(-3*24*time.Hour), // 3 days before
eventDate.Add(-24*time.Hour), // 1 day before
)),
gocron.NewTask(func() {
daysUntil := int(time.Until(eventDate).Hours() / 24)
sendEventReminder(daysUntil)
}),
gocron.WithName("event-reminders"),
)// Update deployment status at specific milestones
deployStart := time.Now()
j, _ := s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartDateTimes(
deployStart.Add(5*time.Minute), // 5 min check
deployStart.Add(15*time.Minute), // 15 min check
deployStart.Add(30*time.Minute), // 30 min check
deployStart.Add(60*time.Minute), // 1 hour check
)),
gocron.NewTask(func() {
status := checkDeploymentStatus()
notifyTeam(status)
}),
gocron.WithName("deployment-checks"),
)func scheduleUserReminder(s gocron.Scheduler, userID string, reminderTime time.Time, message string) error {
_, err := s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartDateTime(reminderTime)),
gocron.NewTask(func(uid, msg string) {
sendUserNotification(uid, msg)
}, userID, message),
gocron.WithName(fmt.Sprintf("reminder-%s-%d", userID, reminderTime.Unix())),
)
return err
}
// Usage
scheduleUserReminder(s, "user-123", time.Now().Add(2*time.Hour), "Meeting in 2 hours")func scheduleOrderTimeout(s gocron.Scheduler, orderID string, timeout time.Duration) error {
timeoutAt := time.Now().Add(timeout)
_, err := s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartDateTime(timeoutAt)),
gocron.NewTask(func(oid string) {
order := getOrder(oid)
if order.Status == "pending" {
cancelOrder(oid)
refundPayment(oid)
notifyUser(order.UserID, "Order cancelled due to timeout")
}
}, orderID),
gocron.WithName(fmt.Sprintf("order-timeout-%s", orderID)),
)
return err
}
// Usage
scheduleOrderTimeout(s, "order-456", 30*time.Minute)func scheduleSessionExpiry(s gocron.Scheduler, sessionID string, expiryTime time.Time) error {
_, err := s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartDateTime(expiryTime)),
gocron.NewTask(func(sid string) {
if sessionExists(sid) {
invalidateSession(sid)
cleanupSessionData(sid)
}
}, sessionID),
gocron.WithName(fmt.Sprintf("session-expiry-%s", sessionID)),
)
return err
}
// Usage
expiryTime := time.Now().Add(24 * time.Hour)
scheduleSessionExpiry(s, "sess-789", expiryTime)// Try immediately, then at intervals, max 3 times
j, _ := s.NewJob(
gocron.DurationJob(5*time.Minute),
gocron.NewTask(func() error {
return attemptConnection()
}),
gocron.WithStartAt(gocron.WithStartImmediately()),
gocron.WithLimitedRuns(3),
gocron.WithName("connection-retry"),
)
// Runs at most 3 times, then removed// Deploy to progressively larger groups
deployGroups := []int{10, 25, 50, 100} // percentage
startTime := time.Now()
for i, percentage := range deployGroups {
deployTime := startTime.Add(time.Duration(i*15) * time.Minute)
s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartDateTime(deployTime)),
gocron.NewTask(func(pct int) {
fmt.Printf("Deploying to %d%% of users\n", pct)
deployToPercentage(pct)
}, percentage),
gocron.WithName(fmt.Sprintf("deploy-stage-%d", i)),
)
}// Schedule a task
reminderTime := time.Now().Add(24 * time.Hour)
j, _ := s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartDateTime(reminderTime)),
gocron.NewTask(sendReminder),
gocron.WithName("payment-reminder"),
)
// Later: user pays, cancel the reminder
if userPaid {
s.RemoveJob(j.ID())
fmt.Println("Reminder cancelled")
}j, _ := s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartImmediately()),
gocron.NewTask(func() {
defer func() {
// Job automatically removed after execution
fmt.Println("One-time job completed and removed")
}()
performTask()
}),
gocron.WithName("self-cleanup"),
)package main
import (
"fmt"
"os"
"os/signal"
"syscall"
"time"
"github.com/go-co-op/gocron/v2"
)
func main() {
s, err := gocron.NewScheduler()
if err != nil {
panic(err)
}
defer s.Shutdown()
// Immediate initialization
s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartImmediately()),
gocron.NewTask(func() {
fmt.Println("Initializing system...")
time.Sleep(2 * time.Second)
fmt.Println("Initialization complete")
}),
gocron.WithName("init"),
)
// Delayed task in 30 seconds
futureTime := time.Now().Add(30 * time.Second)
s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartDateTime(futureTime)),
gocron.NewTask(func() {
fmt.Println("Delayed task executed")
}),
gocron.WithName("delayed-task"),
)
// Multiple scheduled times
s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartDateTimes(
time.Now().Add(1*time.Minute),
time.Now().Add(2*time.Minute),
time.Now().Add(3*time.Minute),
)),
gocron.NewTask(func() {
fmt.Println("Periodic check:", time.Now().Format("15:04:05"))
}),
gocron.WithName("periodic-checks"),
)
// Specific date/time
specificTime := time.Date(
time.Now().Year(),
time.Now().Month(),
time.Now().Day(),
time.Now().Hour(),
time.Now().Minute()+5,
0, 0, time.Local,
)
s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartDateTime(specificTime)),
gocron.NewTask(func() {
fmt.Println("Specific time task executed")
}),
gocron.WithName("specific-time"),
)
// Start scheduler
s.Start()
fmt.Println("Scheduler started with one-time jobs")
// Print schedule
for _, j := range s.Jobs() {
nextRun, _ := j.NextRun()
fmt.Printf("%s: next run at %v\n", j.Name(), nextRun)
}
// Monitor job count
go func() {
ticker := time.NewTicker(10 * time.Second)
defer ticker.Stop()
for range ticker.C {
jobCount := len(s.Jobs())
fmt.Printf("Active jobs: %d\n", jobCount)
if jobCount == 0 {
fmt.Println("All one-time jobs completed")
}
}
}()
// Wait for interrupt
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, os.Interrupt, syscall.SIGTERM)
<-sigCh
fmt.Println("Shutting down...")
}// Run setup tasks in order
s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartImmediately()),
gocron.NewTask(func() {
checkDependencies()
loadConfiguration()
connectToDatabase()
warmupCaches()
fmt.Println("Application ready")
}),
gocron.WithName("startup"),
)// Clean up temporary data after delay
func scheduleCleanup(s gocron.Scheduler, tempID string, delay time.Duration) {
cleanupTime := time.Now().Add(delay)
s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartDateTime(cleanupTime)),
gocron.NewTask(func(id string) {
cleanupTempData(id)
}, tempID),
gocron.WithName(fmt.Sprintf("cleanup-%s", tempID)),
)
}// Enable feature at specific time
rolloutTime := time.Date(2024, 12, 1, 0, 0, 0, 0, time.UTC)
s.NewJob(
gocron.OneTimeJob(gocron.OneTimeJobStartDateTime(rolloutTime)),
gocron.NewTask(func() {
enableFeature("new-ui")
notifyUsers("New UI is now available!")
}),
gocron.WithName("feature-rollout"),
)OneTimeJobWithLimitedRunsInstall with Tessl CLI
npx tessl i tessl/golang-github-com-go-co-op-gocron-v2docs
api
examples
guides