Help us shape the future of Go! Take the 2026 Go Developer Survey

schedule

package
v0.30.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 19, 2026 License: MIT Imports: 10 Imported by: 0

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

Examples

Constants

This section is empty.

Variables

View Source
var ErrCron = errors.New("schedule: invalid cron expression")

ErrCron reports an invalid expression.

View Source
var ErrLocksNotShared = errors.New(
	"schedule: OnOneServer needs a lock store shared by the servers " +
		"(CACHE_STORE=database, Redis, or a custom store implementing cache.Sharer)",
)

ErrLocksNotShared is returned for OnOneServer tasks when Options.Locks is not shared by the servers (cache.Shared is false): the memory cache, or a store that does not declare cache.Sharer.

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

func MustParseCron(expr string) Cron

MustParseCron is ParseCron that panics (for literals).

func ParseCron

func ParseCron(expr string) (Cron, error)

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

func (Cron) Matches

func (c Cron) Matches(t time.Time) bool

Matches reports whether t (to the minute, in t's location) is a run time.

func (Cron) Next

func (c Cron) Next(t time.Time) time.Time

Next returns the first run time strictly after t (in t's location), or the zero time if there is none within five years.

func (Cron) String

func (c Cron) String() string

String returns the expression as given.

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 New

func New(o Options) *Schedule

New returns an empty schedule.

func (*Schedule) Command

func (s *Schedule) Command(name string, args ...string) *Task

Command schedules an app command with args.

func (*Schedule) Due

func (s *Schedule) Due(now time.Time) []*Task

Due returns the tasks due at now (to the minute).

func (*Schedule) Func

func (s *Schedule) Func(name string, fn func(ctx context.Context) error) *Task

Func schedules fn under name.

func (*Schedule) Job

func (s *Schedule) Job(j queue.Job, opts ...queue.Option) *Task

Job schedules dispatching j onto the queue.

func (*Schedule) Next

func (s *Schedule) Next(t *Task, now time.Time) time.Time

Next returns when t runs next after now.

func (*Schedule) RunDue

func (s *Schedule) RunDue(ctx context.Context, now time.Time) error

RunDue runs the tasks due at now concurrently and waits for them. Task errors are logged and joined into the result.

func (*Schedule) Tasks

func (s *Schedule) Tasks() []*Task

Tasks returns the tasks in registration order.

func (*Schedule) Validate added in v0.25.0

func (s *Schedule) Validate() error

Validate reports configuration that cannot work: an OnOneServer task with a lock store that is not shared by the servers (cache.Shared).

func (*Schedule) Work

func (s *Schedule) Work(ctx context.Context, now func() time.Time) error

Work runs due tasks at the start of every minute until ctx is cancelled, then waits for running tasks up to Options.StopTimeout and cancels their context. now is the clock (time.Now if nil).

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

func (t *Task) Cron(expr string) *Task

Cron sets a cron expression; it panics on a bad expression, so mistakes surface at boot.

func (*Task) Daily

func (t *Task) Daily() *Task

Daily runs the task at midnight.

func (*Task) DailyAt

func (t *Task) DailyAt(hhmm string) *Task

DailyAt runs the task every day at "HH:MM"; it panics on a malformed time.

func (*Task) Every

func (t *Task) Every(d time.Duration) *Task

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). It panics on any other d.

func (*Task) EveryFiveMinutes

func (t *Task) EveryFiveMinutes() *Task

EveryFiveMinutes runs the task every five minutes.

func (*Task) EveryMinute

func (t *Task) EveryMinute() *Task

EveryMinute runs the task every minute.

func (*Task) Expression

func (t *Task) Expression() string

Expression returns the cron expression.

func (*Task) Hourly

func (t *Task) Hourly() *Task

Hourly runs the task at the start of every hour.

func (*Task) HourlyAt

func (t *Task) HourlyAt(minute int) *Task

HourlyAt runs the task every hour at minute; it panics unless minute is in 0-59.

func (*Task) In

func (t *Task) In(loc *time.Location) *Task

In sets the time zone of the task's expression.

func (*Task) MonthlyOn

func (t *Task) MonthlyOn(day int, hhmm string) *Task

MonthlyOn runs the task on day of the month at "HH:MM"; it panics on a malformed time or a day outside 1-31.

func (*Task) Name

func (t *Task) Name() string

Name returns the task's label.

func (*Task) OnOneServer added in v0.25.0

func (t *Task) OnOneServer() *Task

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 (cache.Shared: the database or Redis cache, or a wrapper that declares cache.Sharer or exposes Unwrap); with an in-process or undeclared store, where every server could run the task, Validate fails and the task refuses to run (fail closed).

func (*Task) Weekdays

func (t *Task) Weekdays() *Task

Weekdays restricts the task to Monday-Friday (keeps its time).

func (*Task) WeeklyOn

func (t *Task) WeeklyOn(weekday time.Weekday, hhmm string) *Task

WeeklyOn runs the task on weekday (0 = Sunday) at "HH:MM"; it panics on a malformed time or weekday.

func (*Task) WithoutOverlapping

func (t *Task) WithoutOverlapping(ttl ...time.Duration) *Task

WithoutOverlapping skips a run while the previous one still holds the lock (released when it ends, or after ttl; default 24h).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL