scheduler

package
v1.12.0 Latest Latest
Warning

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

Go to latest
Published: Sep 24, 2026 License: MIT Imports: 8 Imported by: 2

Documentation

Index

Constants

View Source
const (
	// DefaultShutdownTimeout is how long Start waits for running jobs after its
	// ctx is done, unless WithShutdownTimeout sets another value.
	DefaultShutdownTimeout = 60 * time.Second
	// DefaultJobTimeout is the per-job timeout applied when the job's ctx has no
	// deadline, unless WithJobTimeout sets another value.
	DefaultJobTimeout = time.Hour
)

Variables

View Source
var ErrSuperseded error = ez.New(ez.ECANCELED, "scheduler: superseded", context.Canceled)

ErrSuperseded is the context cause seen by a job that was cancelled because Supersede queued a replacement for the same id. errors.Is(context.Cause(ctx), ErrSuperseded) and errors.Is(context.Cause(ctx), context.Canceled) both hold.

Functions

func ShouldRunLocalHour added in v1.6.0

func ShouldRunLocalHour(tz string, hour int) bool

ShouldRunLocalHour returns true if the local time in tz is exactly hour:00.

func ShouldRunLocalTime added in v1.6.4

func ShouldRunLocalTime(tz string, hour, minute int) bool

ShouldRunLocalTime returns true if the local time in tzName matches hour:minute exactly.

Types

type Job

type Job func(ctx context.Context)

Job is a unit of work run by the Scheduler. It should return promptly once ctx is done.

type Option added in v1.6.0

type Option func(*Scheduler)

Option configures the Scheduler. Pass options to New.

func WithJobTimeout added in v1.6.0

func WithJobTimeout(d time.Duration) Option

WithJobTimeout sets the per-job timeout applied when the job's ctx has no deadline. The timer starts when the job body is about to run, after any permit from WithLimit was acquired, so time spent waiting for a permit does not count. d <= 0 is ignored.

func WithLimit added in v1.12.0

func WithLimit(prefix string, n int) Option

WithLimit caps at n the number of jobs whose id starts with prefix that run at the same time, across RunOnce, Supersede, RunNext and recurring jobs. A job over the cap waits for a permit, still counts in Active, and gives up without running if its context is cancelled while waiting. New rejects an empty prefix, n < 1, a prefix given twice, and a prefix that is a prefix of another limit's prefix.

func WithLogger added in v1.6.0

func WithLogger(l logger.Logger) Option

WithLogger sets the logger. Nil => Noop logger.

func WithShutdownTimeout added in v1.6.0

func WithShutdownTimeout(d time.Duration) Option

WithShutdownTimeout sets how long Start waits for jobs to drain after its ctx is done. d <= 0 is ignored.

type Schedule added in v1.12.0

type Schedule struct {
	// contains filtered or unexported fields
}

Schedule is an immutable description of the wall-clock minutes at which a recurring job is due. Build it with Every, Hourly or Daily. The zero value is invalid. A value can be reused for several ids.

func Daily added in v1.12.0

func Daily(hour, minute int, loc *time.Location) Schedule

Daily returns a Schedule that is due once a day at hour:minute wall-clock time in loc. hour must be in 0..23, minute in 0..59 and loc non-nil. On a day where that local time does not exist (DST spring-forward) the schedule is not due; on a day where it occurs twice (DST fall-back) it is due at both instants. Invalid input yields a Schedule that Add rejects with an ez.EINVALID error.

func Every added in v1.12.0

func Every(d time.Duration) Schedule

Every returns a Schedule that is due at minute 0 of every hour and every d after it, in server-local time. d must be a whole number of minutes that divides one hour evenly (1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 30 or 60 minutes). Every(time.Hour) is equivalent to Hourly(0). An invalid d yields a Schedule that Add rejects with an ez.EINVALID error.

func Hourly added in v1.12.0

func Hourly(minutes ...int) Schedule

Hourly returns a Schedule that is due at each of the given minutes of every hour, in server-local time. At least one minute is required, each must be in 0..59 and none may repeat. Order does not matter. Invalid input yields a Schedule that Add rejects with an ez.EINVALID error.

type Scheduler

type Scheduler struct {
	// contains filtered or unexported fields
}

Scheduler runs recurring jobs on wall-clock minute boundaries and one-shot jobs on demand. Work is keyed by id: at most one invocation per id runs at a time, and each busy id holds at most one pending job that runs after the current one returns. Create it with New.

func New

func New(opts ...Option) (*Scheduler, error)

New creates a Scheduler with the given options. It returns an ez.EINVALID error when a WithLimit option has an empty prefix, a size below 1, a prefix given twice, or a prefix that is a prefix of another limit's prefix.

func (*Scheduler) Active added in v1.6.2

func (s *Scheduler) Active() int64

Active returns the number of ids with admitted work: running, or waiting for a permit from a WithLimit option. A pending job adds nothing to the count.

func (*Scheduler) Add

func (s *Scheduler) Add(id string, when Schedule, job Job) error

Add registers job to run at the minute boundaries selected by when. It returns an ez.EINVALID error for an empty id, a nil job or an invalid Schedule, and an ez.ECONFLICT error when a recurring job with the same id is already registered; on error nothing is registered. Add may be called before or after Start. The id is shared with RunOnce, Supersede and RunNext: a due boundary is skipped while the id is busy.

Daily schedules follow wall time in their location: on a DST spring-forward day a nonexistent local time does not fire, and on a fall-back day a repeated local time fires at both instants.

func (*Scheduler) Idled added in v1.6.2

func (s *Scheduler) Idled() <-chan struct{}

Idled returns a channel that receives a value when the last busy id finishes and Active drops to zero. It has a buffer of one and sends never block, so a receiver may see one value for several idle transitions. It does not fire between a job and the pending job that follows it. Check Active after receiving, since new work may already have been admitted.

func (*Scheduler) RunNext added in v1.12.0

func (s *Scheduler) RunNext(ctx context.Context, id string, job Job) bool

RunNext starts job under id now when id is idle. When id is busy it replaces the id's pending job with job and returns true without cancelling the current invocation; job starts after the current invocation returns. It returns false when id is empty, job is nil, ctx is already done, or the Scheduler is stopping. A pending job whose ctx is done by then is dropped.

func (*Scheduler) RunOnce

func (s *Scheduler) RunOnce(ctx context.Context, id string, job Job) bool

RunOnce starts job under id now. It returns false without running anything when id is empty, job is nil, ctx is already done, the Scheduler is stopping, or id is busy; a busy id's pending job is left untouched.

func (*Scheduler) Start

func (s *Scheduler) Start(ctx context.Context)

Start runs the minute engine and blocks until ctx is done. It sleeps until the next wall-clock minute boundary, runs the recurring jobs due at it, and repeats. It never fires immediately: the first boundary evaluated is the first one after Start is called.

A late wake, because the process was frozen or the clock jumped forward, catches up: every minute boundary between the last one handled and the clock is evaluated, and a registration due at any of them is admitted once. A due job whose id is still busy is skipped for that wake. Nothing is remembered across restarts, so minutes that pass while the process is not running are never replayed. If the clock is stepped back by a minute or more the engine follows it and evaluates those minutes again as they pass.

When ctx is done Start stops the Scheduler: nothing new is admitted, pending jobs are discarded, running jobs are cancelled with context.Canceled, and Start waits for them up to the shutdown timeout before returning. Jobs that ignore their context may outlive that wait. Call Start once; once it has returned, a later call returns immediately.

func (*Scheduler) Supersede added in v1.12.0

func (s *Scheduler) Supersede(ctx context.Context, id string, job Job) bool

Supersede starts job under id now when id is idle. When id is busy it replaces the id's pending job with job, cancels the current invocation with cause ErrSuperseded and returns true without waiting; job starts after the current invocation returns. It returns false when id is empty, job is nil, ctx is already done, or the Scheduler is stopping.

Jump to

Keyboard shortcuts

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