A fluent, Laravel-inspired scheduler for Go that wraps gocron with expressive APIs for defining, filtering, and controlling scheduled jobs.
- Fluent, chainable API for intervals, cron strings, and calendar helpers (daily/weekly/monthly).
- Overlap protection with optional distributed locking plus per-job tags and metadata.
- Filters (weekdays/weekends/time windows) and hooks (before/after/success/failure) keep jobs predictable.
- Command execution helper for running CLI tasks with background mode and env-aware tagging.
- Auto-generated, compile-tested examples ensure docs and behavior stay in sync.
Go has excellent low-level scheduling libraries, but defining real-world schedules often turns into a maze of cron strings, conditionals, and glue code.
scheduler provides a Laravel-style fluent API on top of gocron that lets you describe when, how, and under what conditions a job should run - without hiding what’s actually happening.
Everything remains explicit, testable, and inspectable, while staying pleasant to read and maintain.
scheduler.NewJobBuilder(s).
Name("reports:generate").
Weekdays().
Between("09:00", "17:00").
WithoutOverlapping().
DailyAt("10:30").
Do(func() {
generateReports()
})package main
import (
"github.com/go-co-op/gocron/v2"
"github.com/goforj/scheduler"
)
func main() {
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).
EveryMinute().
Name("cleanup").
Do(func() {})
scheduler.NewJobBuilder(s).PrintJobsList()
}Example output:
+--------------------------------------------------------------------------------------+
| Scheduler Jobs › (3)
+----------------+----------+----------------+---------+--------+----------------------+
| Name | Type | Schedule | Handler | Next | Tags |
+----------------+----------+----------------+---------+--------+----------------------+
| hello:world | command | cron 0 0 * * 0 | - | in 3d | env=dev, args="w" |
| hello:world | command | every 1h | - | in 1h | env=dev, args="hour" |
| cleanup | function | every 1m | cleanup | in 1m | env=dev |
+----------------+----------+----------------+---------+--------+----------------------+
Every function has a corresponding runnable example under ./examples.
These examples are generated directly from the documentation blocks of each function, ensuring the docs and code never drift. These are the same examples you see here in the README and GoDoc.
An automated test executes every example to verify it builds and runs successfully.
This guarantees all examples are valid, up-to-date, and remain functional as the API evolves.
Lock invokes the underlying function.
client := redis.NewClient(&redis.Options{})
locker := scheduler.NewRedisLocker(client, time.Minute)
lock, _ := locker.Lock(context.Background(), "job")
_ = lock.Unlock(context.Background())Run executes the underlying function.
runner := scheduler.CommandRunnerFunc(func(ctx context.Context, exe string, args []string) error {
return nil
})
_ = runner.Run(context.Background(), "echo", []string{"hi"})Unlock invokes the underlying function.
Command executes the current binary with the given subcommand and variadic args.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).
Cron("0 0 * * *").
Command("jobs:purge", "--force")WithoutOverlapping ensures the job does not run concurrently.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).
WithoutOverlapping().
EveryFiveSeconds().
Do(func() { time.Sleep(7 * time.Second) })WithoutOverlappingWithLocker ensures the job does not run concurrently across distributed systems using the provided locker.
locker := scheduler.LockerFunc(func(ctx context.Context, key string) (gocron.Lock, error) {
return scheduler.LockFunc(func(context.Context) error { return nil }), nil
})
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).
WithoutOverlappingWithLocker(locker).
EveryMinute().
Do(func() {})Timezone sets a timezone string for the job (not currently applied to gocron Scheduler).
scheduler.NewJobBuilder(nil).
Timezone("America/New_York").
Daily()WithCommandRunner overrides command execution (default: exec.CommandContext).
runner := scheduler.CommandRunnerFunc(func(_ context.Context, exe string, args []string) error {
fmt.Println(exe, args)
return nil
})
builder := scheduler.NewJobBuilder(nil).
WithCommandRunner(runner)
fmt.Printf("%T\n", builder)WithNowFunc overrides current time (default: time.Now). Useful for tests.
fixed := func() time.Time { return time.Unix(0, 0) }
scheduler.NewJobBuilder(nil).WithNowFunc(fixed)NewJobBuilder creates a new JobBuilder with the provided scheduler.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).EverySecond().Do(func() {})CronExpr returns the cron expression string configured for this job.
builder := scheduler.NewJobBuilder(nil).Cron("0 9 * * *")
fmt.Println(builder.CronExpr())Error returns the error if any occurred during job scheduling.
builder := scheduler.NewJobBuilder(nil).DailyAt("bad")
fmt.Println(builder.Error())Job returns the last scheduled gocron.Job instance, if available.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
b := scheduler.NewJobBuilder(s).EverySecond().Do(func() {})
fmt.Println(b.Job() != nil)PrintJobsList renders and prints the scheduler job table to stdout.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).
EverySecond().
Name("heartbeat").
Do(func() {})
scheduler.NewJobBuilder(s).PrintJobsList()RunInBackground runs command/exec tasks in a goroutine.
scheduler.NewJobBuilder(nil).
RunInBackground().
Command("noop")Between limits the job to run between the provided HH:MM times (inclusive).
scheduler.NewJobBuilder(nil).
Between("09:00", "17:00").
EveryMinute()Days limits the job to a specific set of weekdays.
scheduler.NewJobBuilder(nil).
Days(time.Monday, time.Wednesday, time.Friday).
DailyAt("07:00")Environments restricts job registration to specific environment names (e.g. "production", "staging").
scheduler.NewJobBuilder(nil).Environments("production").Daily()Fridays limits the job to Fridays.
scheduler.NewJobBuilder(nil).Fridays().DailyAt("09:00")Mondays limits the job to Mondays.
scheduler.NewJobBuilder(nil).Mondays().DailyAt("09:00")Saturdays limits the job to Saturdays.
scheduler.NewJobBuilder(nil).Saturdays().DailyAt("09:00")Skip prevents scheduling the job if the provided condition returns true.
enabled := false
scheduler.NewJobBuilder(nil).
Skip(func() bool { return !enabled }).
Daily()Sundays limits the job to Sundays.
scheduler.NewJobBuilder(nil).Sundays().DailyAt("09:00")Thursdays limits the job to Thursdays.
scheduler.NewJobBuilder(nil).Thursdays().DailyAt("09:00")Tuesdays limits the job to Tuesdays.
scheduler.NewJobBuilder(nil).Tuesdays().DailyAt("09:00")UnlessBetween prevents the job from running between the provided HH:MM times.
scheduler.NewJobBuilder(nil).
UnlessBetween("22:00", "06:00").
EveryMinute()Wednesdays limits the job to Wednesdays.
scheduler.NewJobBuilder(nil).Wednesdays().DailyAt("09:00")Weekdays limits the job to run only on weekdays (Mon-Fri).
scheduler.NewJobBuilder(nil).Weekdays().DailyAt("09:00")Weekends limits the job to run only on weekends (Sat-Sun).
scheduler.NewJobBuilder(nil).Weekends().DailyAt("10:00")When only schedules the job if the provided condition returns true.
flag := true
scheduler.NewJobBuilder(nil).
When(func() bool { return flag }).
Daily()After sets a hook to run after task execution.
scheduler.NewJobBuilder(nil).
After(func() { println("after") }).
Daily()Before sets a hook to run before task execution.
scheduler.NewJobBuilder(nil).
Before(func() { println("before") }).
Daily()OnFailure sets a hook to run after failed task execution.
scheduler.NewJobBuilder(nil).
OnFailure(func() { println("failure") }).
Daily()OnSuccess sets a hook to run after successful task execution.
scheduler.NewJobBuilder(nil).
OnSuccess(func() { println("success") }).
Daily()NewRedisLocker creates a RedisLocker with a client and TTL.
client := redis.NewClient(&redis.Options{}) // replace with your client
locker := scheduler.NewRedisLocker(client, time.Minute)
_, _ = locker.Lock(context.Background(), "job")JobMetadata returns a copy of the tracked job metadata keyed by job ID.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
b := scheduler.NewJobBuilder(s).EverySecond().Do(func() {})
for id, meta := range b.JobMetadata() {
_ = id
_ = meta.Name
}Name sets an explicit job name.
scheduler.NewJobBuilder(nil).
Name("cache:refresh").
HourlyAt(15)Cron sets the cron expression for the job.
builder := scheduler.NewJobBuilder(nil).Cron("15 3 * * *")
fmt.Println(builder.CronExpr())Daily schedules the job to run once per day at midnight.
scheduler.NewJobBuilder(nil).Daily()DailyAt schedules the job to run daily at a specific time (e.g., "13:00").
scheduler.NewJobBuilder(nil).DailyAt("12:30")DaysOfMonth schedules the job to run on specific days of the month at a given time.
scheduler.NewJobBuilder(nil).DaysOfMonth([]int{5, 20}, "07:15")Do schedules the job with the provided task function.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).
Name("cleanup").
Cron("0 0 * * *").
Do(func() {})Every schedules a job to run every X seconds, minutes, or hours.
scheduler.NewJobBuilder(nil).
Every(10).
Minutes()EveryFifteenMinutes schedules the job to run every 15 minutes.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).EveryFifteenMinutes().Do(func() {})EveryFifteenSeconds schedules the job to run every 15 seconds.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).EveryFifteenSeconds().Do(func() {})EveryFiveMinutes schedules the job to run every 5 minutes.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).EveryFiveMinutes().Do(func() {})EveryFiveSeconds schedules the job to run every 5 seconds.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).EveryFiveSeconds().Do(func() {})EveryFourHours schedules the job to run every four hours at the specified minute.
scheduler.NewJobBuilder(nil).EveryFourHours(25)EveryFourMinutes schedules the job to run every 4 minutes.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).EveryFourMinutes().Do(func() {})EveryMinute schedules the job to run every 1 minute.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).EveryMinute().Do(func() {})EveryOddHour schedules the job to run every odd-numbered hour at the specified minute.
scheduler.NewJobBuilder(nil).EveryOddHour(10)EverySecond schedules the job to run every 1 second.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).EverySecond().Do(func() {})EverySixHours schedules the job to run every six hours at the specified minute.
scheduler.NewJobBuilder(nil).EverySixHours(30)EveryTenMinutes schedules the job to run every 10 minutes.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).EveryTenMinutes().Do(func() {})EveryTenSeconds schedules the job to run every 10 seconds.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).EveryTenSeconds().Do(func() {})EveryThirtyMinutes schedules the job to run every 30 minutes.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).EveryThirtyMinutes().Do(func() {})EveryThirtySeconds schedules the job to run every 30 seconds.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).EveryThirtySeconds().Do(func() {})EveryThreeHours schedules the job to run every three hours at the specified minute.
scheduler.NewJobBuilder(nil).EveryThreeHours(20)EveryThreeMinutes schedules the job to run every 3 minutes.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).EveryThreeMinutes().Do(func() {})EveryTwentySeconds schedules the job to run every 20 seconds.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).EveryTwentySeconds().Do(func() {})EveryTwoHours schedules the job to run every two hours at the specified minute.
scheduler.NewJobBuilder(nil).EveryTwoHours(15)EveryTwoMinutes schedules the job to run every 2 minutes.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).EveryTwoMinutes().Do(func() {})EveryTwoSeconds schedules the job to run every 2 seconds.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).EveryTwoSeconds().Do(func() {})Hourly schedules the job to run every hour.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).Hourly().Do(func() {})HourlyAt schedules the job to run every hour at the specified minute.
scheduler.NewJobBuilder(nil).HourlyAt(5)Hours schedules the job to run every X hours.
scheduler.NewJobBuilder(nil).Every(6).Hours()LastDayOfMonth schedules the job to run on the last day of each month at a specific time.
scheduler.NewJobBuilder(nil).LastDayOfMonth("23:30")Minutes schedules the job to run every X minutes.
scheduler.NewJobBuilder(nil).Every(15).Minutes()Monthly schedules the job to run on the first day of each month at midnight.
scheduler.NewJobBuilder(nil).Monthly()MonthlyOn schedules the job to run on a specific day of the month at a given time.
scheduler.NewJobBuilder(nil).MonthlyOn(15, "09:30")Quarterly schedules the job to run on the first day of each quarter at midnight.
scheduler.NewJobBuilder(nil).Quarterly()QuarterlyOn schedules the job to run on a specific day of each quarter at a given time.
scheduler.NewJobBuilder(nil).QuarterlyOn(3, "12:00")Seconds schedules the job to run every X seconds.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
scheduler.NewJobBuilder(s).
Every(3).
Seconds().
Do(func() {})TwiceDaily schedules the job to run daily at two specified hours (e.g., 1 and 13).
scheduler.NewJobBuilder(nil).TwiceDaily(1, 13)TwiceDailyAt schedules the job to run daily at two specified times (e.g., 1:15 and 13:15).
scheduler.NewJobBuilder(nil).TwiceDailyAt(1, 13, 15)TwiceMonthly schedules the job to run on two specific days of the month at the given time.
scheduler.NewJobBuilder(nil).TwiceMonthly(1, 15, "10:00")Weekly schedules the job to run once per week on Sunday at midnight.
scheduler.NewJobBuilder(nil).Weekly()WeeklyOn schedules the job to run weekly on a specific day of the week and time. Day uses 0 = Sunday through 6 = Saturday.
scheduler.NewJobBuilder(nil).WeeklyOn(1, "8:00")Yearly schedules the job to run on January 1st every year at midnight.
scheduler.NewJobBuilder(nil).Yearly()YearlyOn schedules the job to run every year on a specific month, day, and time.
scheduler.NewJobBuilder(nil).YearlyOn(12, 25, "06:45")RetainState allows the job to retain its state after execution.
s, _ := gocron.NewScheduler()
s.Start()
defer s.Shutdown()
builder := scheduler.NewJobBuilder(s).EverySecond().RetainState()
builder.Do(func() {})
builder.Do(func() {})