Documentation
¶
Overview ¶
Package schedule runs recurring tasks: functions, app commands and queue jobs, on cron expressions or helpers such as DailyAt.
s.Command("reports:send").DailyAt("08:00").WithoutOverlapping()
s.Job(jobs.PruneSessions{}).Hourly()
s.Func("ping", func(ctx context.Context) error { ... }).EveryFiveMinutes()
Run it in process with Work (vukem schedule:work) or from one cron entry calling RunDue every minute (vukem schedule:run). Schedule holds the Task list, Cron parses five-field expressions, and WithoutOverlapping takes a lock in the Options.Locks cache.
See https://github.com/AlexGalhardo/vukem/blob/main/docs/subsystems.md#scheduler.
Example ¶
package main
import (
"context"
"fmt"
"time"
"github.com/AlexGalhardo/vukem/schedule"
)
func main() {
s := schedule.New(schedule.Options{})
s.Func("ping", func(context.Context) error { return nil }).EveryFiveMinutes()
s.Command("reports:send").DailyAt("08:00").WithoutOverlapping()
for _, t := range s.Tasks() {
fmt.Println(t.Name(), t.Expression())
}
now := time.Date(2026, 1, 5, 8, 0, 0, 0, time.UTC)
for _, t := range s.Due(now) {
fmt.Println("due at 08:00:", t.Name())
}
}
Output: ping */5 * * * * reports:send 0 8 * * * due at 08:00: ping due at 08:00: reports:send
Index ¶
- Variables
- type Cron
- type Options
- type Schedule
- func (s *Schedule) Command(name string, args ...string) *Task
- func (s *Schedule) Due(now time.Time) []*Task
- func (s *Schedule) Func(name string, fn func(ctx context.Context) error) *Task
- func (s *Schedule) Job(j queue.Job, opts ...queue.Option) *Task
- func (s *Schedule) Next(t *Task, now time.Time) time.Time
- func (s *Schedule) RunDue(ctx context.Context, now time.Time) error
- func (s *Schedule) Tasks() []*Task
- func (s *Schedule) Validate() error
- func (s *Schedule) Work(ctx context.Context, now func() time.Time) error
- type Task
- func (t *Task) Cron(expr string) *Task
- func (t *Task) Daily() *Task
- func (t *Task) DailyAt(hhmm string) *Task
- func (t *Task) Every(d time.Duration) *Task
- func (t *Task) EveryFiveMinutes() *Task
- func (t *Task) EveryMinute() *Task
- func (t *Task) Expression() string
- func (t *Task) Hourly() *Task
- func (t *Task) HourlyAt(minute int) *Task
- func (t *Task) In(loc *time.Location) *Task
- func (t *Task) MonthlyOn(day int, hhmm string) *Task
- func (t *Task) Name() string
- func (t *Task) OnOneServer() *Task
- func (t *Task) Weekdays() *Task
- func (t *Task) WeeklyOn(weekday time.Weekday, hhmm string) *Task
- func (t *Task) WithoutOverlapping(ttl ...time.Duration) *Task
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ErrCron = errors.New("schedule: invalid cron expression")
ErrCron reports an invalid expression.
"schedule: OnOneServer needs a lock store shared by the servers (CACHE_STORE=database or Redis)",
)
ErrLocksNotShared is returned for OnOneServer tasks when Options.Locks is an in-process store (the memory cache).
Functions ¶
This section is empty.
Types ¶
type Cron ¶
type Cron struct {
// contains filtered or unexported fields
}
Cron is a parsed five-field cron expression (minute hour day-of-month month day-of-week) with the usual syntax: "*", "5", "1-5", "*/15", "10-50/10", lists ("1,15"), month and weekday names ("JAN", "MON"), and the macros @yearly, @monthly, @weekly, @daily, @hourly. As in Vixie cron, when both day fields are restricted a day matches either.
func MustParseCron ¶
MustParseCron is ParseCron that panics (for literals).
func ParseCron ¶
ParseCron parses expr.
Example ¶
package main
import (
"fmt"
"time"
"github.com/AlexGalhardo/vukem/schedule"
)
func main() {
c, err := schedule.ParseCron("30 9 * * 1-5")
if err != nil {
fmt.Println(err)
return
}
from := time.Date(2026, 1, 3, 12, 0, 0, 0, time.UTC) // a Saturday
fmt.Println(c.Next(from).Format(time.RFC1123))
}
Output: Mon, 05 Jan 2026 09:30:00 UTC
type Options ¶
type Options struct {
// Location is the default time zone of expressions (default UTC).
Location *time.Location
// Log receives task outcomes (default slog.Default()).
Log *slog.Logger
// Locks backs WithoutOverlapping (default an in-memory store, which
// only protects one process; use the database or Redis cache store
// when several servers run the schedule).
Locks *cache.Cache
// Namespace keeps the locks of WithoutOverlapping and OnOneServer apart
// when several apps share one lock store (app.Schedule passes the
// normalized APP_NAME). Empty keeps the keys of v0.24.0.
Namespace string
// Commands runs app commands for Command tasks.
Commands func(ctx context.Context, name string, args []string) error
// Queue dispatches Job tasks.
Queue func() (*queue.Queue, error)
// StopTimeout is how long Work waits for running tasks once its
// context is cancelled before cancelling theirs (default 30s). Tasks
// must honor ctx; one that ignores it still holds Work.
StopTimeout time.Duration
}
Options configure a Schedule.
type Schedule ¶
type Schedule struct {
// contains filtered or unexported fields
}
Schedule holds the tasks.
func (*Schedule) RunDue ¶
RunDue runs the tasks due at now concurrently and waits for them. Task errors are logged and joined into the result.
type Task ¶
type Task struct {
// contains filtered or unexported fields
}
Task is a scheduled unit of work; configure it with the chained methods.
func (*Task) Cron ¶
Cron sets a cron expression; it panics on a bad expression, so mistakes surface at boot.
func (*Task) Every ¶
Every runs the task every d, aligned to the clock (d must be a whole number of minutes dividing an hour or a day, e.g. 5m, 15m, 2h).
func (*Task) EveryFiveMinutes ¶
EveryFiveMinutes runs the task every five minutes.
func (*Task) EveryMinute ¶
EveryMinute runs the task every minute.
func (*Task) Expression ¶
Expression returns the cron expression.
func (*Task) OnOneServer ¶ added in v0.25.0
OnOneServer runs each occurrence of the task on one server only: the first scheduler to take the occurrence's lock (task name and minute) in Options.Locks runs it, the others skip it. The lock store must be shared by the servers (database or Redis cache); with an in-process store, where every server would run the task, Validate fails and the task refuses to run (fail closed).