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

scheduling-strategies.mddocs/guides/jobs/

Scheduling Strategies

How to choose between duration, cron, and time-based schedules for your jobs.

Overview

gocron provides three main scheduling strategies:

  1. Duration-based — Fixed intervals (DurationJob, DurationRandomJob)
  2. Cron-based — Cron expressions (CronJob)
  3. Time-based — Calendar schedules (DailyJob, WeeklyJob, MonthlyJob, OneTimeJob)

Each has different strengths and use cases.

Duration-Based Schedules

DurationJob

func DurationJob(duration time.Duration) JobDefinition

Runs every duration:

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

When to use:

  • Regular, consistent intervals
  • Polling or monitoring tasks
  • Background processing
  • Simple schedules without time-of-day requirements

Strengths:

  • Simple and predictable
  • No timezone concerns
  • Easy to reason about
  • Works well across restarts

Limitations:

  • No alignment to clock time (9 AM, midnight, etc.)
  • Can drift over time
  • No business calendar awareness

Examples:

// Health checks every 30 seconds
gocron.DurationJob(30*time.Second)

// Cache refresh every 5 minutes
gocron.DurationJob(5*time.Minute)

// Backup every hour
gocron.DurationJob(time.Hour)

// Daily cleanup at 24-hour intervals
gocron.DurationJob(24*time.Hour)

DurationRandomJob

func DurationRandomJob(min, max time.Duration) JobDefinition

Runs at random intervals:

j, _ := s.NewJob(
    gocron.DurationRandomJob(time.Minute, 5*time.Minute),
    gocron.NewTask(myFunc),
)

When to use:

  • Prevent thundering herd
  • Spread load across time
  • Avoid synchronized bursts (multiple instances)
  • Simulate randomness

Strengths:

  • Prevents synchronized execution
  • Natural jitter
  • Reduces peak load

Limitations:

  • Unpredictable timing
  • Hard to reason about exact behavior
  • Not suitable for time-critical tasks

Examples:

// Metrics collection with jitter (1-5 minutes)
gocron.DurationRandomJob(time.Minute, 5*time.Minute)

// API polling with randomness (30s - 2min)
gocron.DurationRandomJob(30*time.Second, 2*time.Minute)

Cron-Based Schedules

CronJob

func CronJob(cronExpression string, withSeconds bool) JobDefinition

Runs according to cron expression:

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

// Every 15 minutes
j, _ = s.NewJob(
    gocron.CronJob("*/15 * * * *", false),
    gocron.NewTask(myFunc),
)

// With seconds: every 30 seconds
j, _ = s.NewJob(
    gocron.CronJob("30 * * * * *", true),
    gocron.NewTask(myFunc),
)

When to use:

  • Familiar with cron syntax
  • Complex time-based patterns
  • Need second-level precision
  • Porting from cron

Strengths:

  • Powerful and flexible
  • Industry standard syntax
  • Supports complex patterns
  • Second-level precision available

Limitations:

  • Syntax can be cryptic
  • Easy to make mistakes
  • Harder to read than time-based alternatives
  • No type safety

Cron Format:

5 fields (withSeconds=false):
minute hour day month weekday
0-59   0-23 1-31 1-12  0-6

6 fields (withSeconds=true):
second minute hour day month weekday
0-59   0-59   0-23 1-31 1-12  0-6

Common Patterns:

// Every minute
"* * * * *"

// Every hour at minute 0
"0 * * * *"

// Every day at midnight
"0 0 * * *"

// Every day at 9 AM
"0 9 * * *"

// Every Monday at 9 AM
"0 9 * * 1"

// Every weekday (Mon-Fri) at 9 AM
"0 9 * * 1-5"

// Every 15 minutes
"*/15 * * * *"

// Every hour between 9 AM and 5 PM, Mon-Fri
"0 9-17 * * 1-5"

// First day of every month at midnight
"0 0 1 * *"

Time-Based Schedules

DailyJob

func DailyJob(interval uint, atTimes AtTimes) JobDefinition

Runs every interval days at specific times:

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

When to use:

  • Daily tasks at specific times
  • Readable alternative to cron
  • Multiple times per day
  • Multi-day intervals

Strengths:

  • Readable and clear
  • Type-safe (compile-time checks)
  • Explicit time specification
  • Easy to understand

Examples:

// Every day at 9 AM
gocron.DailyJob(1, gocron.NewAtTimes(gocron.NewAtTime(9, 0, 0)))

// Every day at 9 AM and 5 PM
gocron.DailyJob(
    1,
    gocron.NewAtTimes(
        gocron.NewAtTime(9, 0, 0),
        gocron.NewAtTime(17, 0, 0),
    ),
)

// Every 2 days at noon
gocron.DailyJob(2, gocron.NewAtTimes(gocron.NewAtTime(12, 0, 0)))

WeeklyJob

func WeeklyJob(interval uint, daysOfTheWeek Weekdays, atTimes AtTimes) JobDefinition

Runs every interval weeks on specific days:

// Every Monday at 9 AM
j, _ := s.NewJob(
    gocron.WeeklyJob(
        1,
        gocron.NewWeekdays(time.Monday),
        gocron.NewAtTimes(gocron.NewAtTime(9, 0, 0)),
    ),
    gocron.NewTask(myFunc),
)

When to use:

  • Weekly schedules
  • Specific weekdays
  • Business day schedules
  • Weekend maintenance

Strengths:

  • Readable weekday names
  • Multiple days per week
  • Type-safe

Examples:

// Every Monday at 9 AM
gocron.WeeklyJob(
    1,
    gocron.NewWeekdays(time.Monday),
    gocron.NewAtTimes(gocron.NewAtTime(9, 0, 0)),
)

// Every Monday and Friday at 9 AM
gocron.WeeklyJob(
    1,
    gocron.NewWeekdays(time.Monday, time.Friday),
    gocron.NewAtTimes(gocron.NewAtTime(9, 0, 0)),
)

// Every Saturday at 3 AM (maintenance)
gocron.WeeklyJob(
    1,
    gocron.NewWeekdays(time.Saturday),
    gocron.NewAtTimes(gocron.NewAtTime(3, 0, 0)),
)

// Every 2 weeks on Friday at 5 PM
gocron.WeeklyJob(
    2,
    gocron.NewWeekdays(time.Friday),
    gocron.NewAtTimes(gocron.NewAtTime(17, 0, 0)),
)

MonthlyJob

func MonthlyJob(interval uint, daysOfTheMonth DaysOfTheMonth, atTimes AtTimes) JobDefinition

Runs every interval months on specific days:

// First day of every month at noon
j, _ := s.NewJob(
    gocron.MonthlyJob(
        1,
        gocron.NewDaysOfTheMonth(1),
        gocron.NewAtTimes(gocron.NewAtTime(12, 0, 0)),
    ),
    gocron.NewTask(myFunc),
)

// Last day of every month at midnight
j, _ = s.NewJob(
    gocron.MonthlyJob(
        1,
        gocron.NewDaysOfTheMonth(-1),
        gocron.NewAtTimes(gocron.NewAtTime(0, 0, 0)),
    ),
    gocron.NewTask(myFunc),
)

When to use:

  • Monthly billing/reports
  • End-of-month processing
  • Quarterly tasks
  • Fiscal period schedules

Strengths:

  • Negative day indexing (last day, etc.)
  • Handles variable month lengths
  • Multiple days per month

Examples:

// First of every month at midnight
gocron.MonthlyJob(1, gocron.NewDaysOfTheMonth(1), gocron.NewAtTimes(gocron.NewAtTime(0, 0, 0)))

// Last day of every month
gocron.MonthlyJob(1, gocron.NewDaysOfTheMonth(-1), gocron.NewAtTimes(gocron.NewAtTime(23, 59, 0)))

// 15th and last day of every month
gocron.MonthlyJob(1, gocron.NewDaysOfTheMonth(15, -1), gocron.NewAtTimes(gocron.NewAtTime(12, 0, 0)))

// Every 3 months on the 1st (quarterly)
gocron.MonthlyJob(3, gocron.NewDaysOfTheMonth(1), gocron.NewAtTimes(gocron.NewAtTime(0, 0, 0)))

OneTimeJob

func OneTimeJob(startAt OneTimeJobStartAtOption) JobDefinition

Runs once, then automatically removed:

// Run immediately
j, _ := s.NewJob(
    gocron.OneTimeJob(gocron.OneTimeJobStartImmediately()),
    gocron.NewTask(myFunc),
)

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

When to use:

  • Initialization tasks
  • Warmup on startup
  • Delayed tasks
  • One-time notifications

Strengths:

  • Automatic cleanup
  • Simple delayed execution
  • Can run immediately or at specific time

See Advanced: Time-Based Scheduling for complete details.

Decision Matrix

By Interval Type

NeedUse
Every N seconds/minutes/hoursDurationJob
Random intervalsDurationRandomJob
Complex time patternCronJob
Every day at specific timeDailyJob
Specific weekdaysWeeklyJob
Specific days of monthMonthlyJob
Run onceOneTimeJob

By Readability

PriorityBest Choice
Most readableDailyJob, WeeklyJob, MonthlyJob
Familiar to cron usersCronJob
Simple intervalsDurationJob
RandomnessDurationRandomJob

By Precision

PrecisionOptions
SecondsDurationJob, CronJob (withSeconds=true)
MinutesAll types
Specific time of dayDailyJob, WeeklyJob, MonthlyJob, CronJob
Specific weekdayWeeklyJob, CronJob
Specific day of monthMonthlyJob, CronJob

Comparison Examples

"Every 5 minutes"

// Duration: Simple and clear
gocron.DurationJob(5*time.Minute)

// Cron: More complex, same result
gocron.CronJob("*/5 * * * *", false)

Recommendation: Use DurationJob for simplicity.

"Every day at 9 AM"

// Daily: Most readable
gocron.DailyJob(1, gocron.NewAtTimes(gocron.NewAtTime(9, 0, 0)))

// Cron: More concise if familiar
gocron.CronJob("0 9 * * *", false)

Recommendation: Use DailyJob for clarity, CronJob if you prefer cron syntax.

"Every Monday at 9 AM"

// Weekly: Most readable
gocron.WeeklyJob(
    1,
    gocron.NewWeekdays(time.Monday),
    gocron.NewAtTimes(gocron.NewAtTime(9, 0, 0)),
)

// Cron: More concise
gocron.CronJob("0 9 * * 1", false)

Recommendation: Use WeeklyJob for readability.

"Last day of every month"

// Monthly: Handles variable month lengths
gocron.MonthlyJob(
    1,
    gocron.NewDaysOfTheMonth(-1),
    gocron.NewAtTimes(gocron.NewAtTime(0, 0, 0)),
)

// Cron: Cannot express "last day"
// Would need: "0 0 28-31 * *" (and check if it's last day)

Recommendation: Use MonthlyJob — cron cannot properly express this.

"Business hours: Mon-Fri, 9 AM - 5 PM, every hour"

// Cron: Perfect for this pattern
gocron.CronJob("0 9-17 * * 1-5", false)

// Weekly: Would need 45 jobs (5 days × 9 hours)
// Not practical

Recommendation: Use CronJob for complex patterns.

Best Practices

1. Choose by Readability First

// Good: readable
gocron.DailyJob(1, gocron.NewAtTimes(gocron.NewAtTime(9, 0, 0)))

// Less clear: requires cron knowledge
gocron.CronJob("0 9 * * *", false)

2. Use Duration for Simple Intervals

// Good: simple and clear
gocron.DurationJob(5*time.Minute)

// Overkill: unnecessary complexity
gocron.CronJob("*/5 * * * *", false)

3. Use Cron for Complex Patterns

// Good: perfect for business hours
gocron.CronJob("0 9-17 * * 1-5", false)

// Bad: would require multiple jobs
// gocron.WeeklyJob(...)

4. Consider Timezone for Time-Based

// Set scheduler timezone
loc, _ := time.LoadLocation("America/New_York")
s, _ := gocron.NewScheduler(gocron.WithLocation(loc))

// All time-based jobs use this timezone
s.NewJob(
    gocron.DailyJob(1, gocron.NewAtTimes(gocron.NewAtTime(9, 0, 0))),
    gocron.NewTask(myFunc),
)

5. Use OneTimeJob for Initialization

// Warmup immediately, then regular schedule
s.NewJob(
    gocron.OneTimeJob(gocron.OneTimeJobStartImmediately()),
    gocron.NewTask(warmup),
)

s.NewJob(
    gocron.DurationJob(time.Hour),
    gocron.NewTask(warmup),
)

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