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

one-time-jobs.mddocs/examples/by-task/

One-Time Jobs Examples

Schedule jobs to run once, either immediately or at specific times.

Immediate Execution

Run Immediately Once

j, _ := s.NewJob(
    gocron.OneTimeJob(gocron.OneTimeJobStartImmediately()),
    gocron.NewTask(doInitialization),
)
// Runs once when scheduler starts, then removed

Initialization Task

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

Database Migration

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

Scheduled One-Time Execution

Run at Specific Time

// Run in 1 hour
futureTime := time.Now().Add(time.Hour)
j, _ := s.NewJob(
    gocron.OneTimeJob(gocron.OneTimeJobStartDateTime(futureTime)),
    gocron.NewTask(doDelayedTask),
)

Scheduled Notification

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

Specific Date and Time

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

Trial Expiration

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

Multiple Scheduled Times

Run at Multiple Times

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 removed

Multiple Holiday Notifications

j, _ := 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),
)

Reminder Series

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

Scheduled Status Updates

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

Dynamic One-Time Jobs

User-Triggered Reminder

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")

Order Processing Timeout

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)

Session Expiration

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)

Combining with Limited Runs

Retry with Limit

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

Staged Rollout

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

Cleanup and Cancellation

Cancel Scheduled One-Time Job

// 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")
}

Self-Cleanup Pattern

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

Complete One-Time Jobs Example

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...")
}

Use Cases

Application Startup

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

Delayed Cleanup

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

Feature Flag Rollout

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

Related Documentation

  • API: Job DefinitionsOneTimeJob
  • API: Job OptionsWithLimitedRuns
  • Guide: Job Lifecycle
  • Examples: Interval Scheduling

Install with Tessl CLI

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

docs

index.md

tile.json