cron

package module
v0.5.4 Latest Latest
Warning

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

Go to latest
Published: Aug 20, 2026 License: MIT Imports: 17 Imported by: 0

README

cron

Go Reference Test

A context-aware Go scheduler with typed workflows, explicit lifecycle control, missed-fire policies, and optional distributed coordination. Requires Go 1.27.

go get github.com/libtnb/cron

Quick start

c := cron.MustNew(cron.WithLocation(time.UTC))

_, err := c.Add("0 9 * * MON-FRI", cron.JobFunc(func(ctx context.Context) error {
	return sendDigest(ctx)
}), cron.WithName("digest"))
if err != nil {
	log.Fatal(err)
}

if err := c.Start(); err != nil {
	log.Fatal(err)
}
defer func() {
	if err := c.Stop(context.Background()); err != nil {
		log.Printf("stop cron: %v", err)
	}
}()

The built-in parser uses five fields and accepts descriptors such as @hourly, @every 10s, and CRON_TZ=Asia/Taipei. WithSecondsField enables an optional leading seconds field. Programmatic schedules include OnceAt, ConstantDelay, AlignedDelay, TriggeredSchedule, Union, and Filter.

Entries have stable EntryID values and may be paused, resumed, updated, triggered, inspected, or removed. Stop cancels running jobs; Drain lets them finish. Both are bounded by the supplied context. Missed fires default to MissedSkip; MissedRunOnce and MissedRunAll enable catch-up.

Typed workflows

Go 1.27 generic methods keep workflow data flow type-safe:

b := workflow.New(workflow.WithMaxParallelism(8))

download := b.Step[[]byte]("download", func(ctx context.Context, _ workflow.Inputs) ([]byte, error) {
	return fetch(ctx)
})

b.Step[int]("store", func(ctx context.Context, in workflow.Inputs) (int, error) {
	data, ok := in.Get(download)
	if !ok {
		return 0, errors.New("download output unavailable")
	}
	return save(ctx, data)
}, workflow.After(download, workflow.OnSuccess))

wf := b.MustBuild() // Build freezes the graph.

The executor is bounded (32 concurrent steps by default). Dependencies may use OnSuccess, OnFailure, OnSkipped, or OnComplete; Execute returns typed outputs and per-step results.

Distributed coordination

Claimer.Claim elects one replica for each keyed fire. Elector.IsLeader restricts automatic fires to the current leader. false, nil is normal contention/follower state; backend errors fail closed. Manual triggers bypass coordination.

c := cron.MustNew(cron.WithClaimer(claimer))
_, err := c.Add("0 * * * *", job, cron.WithKey("hourly-report"))

WithKey is the stable cross-replica identity; WithName is only a display label. Redis and PostgreSQL implementations are separate modules:

go get github.com/libtnb/cron/coordination/redis
go get github.com/libtnb/cron/coordination/postgres

Events and metrics

WithObservers delivers typed Event values asynchronously through a bounded, lossy queue. WithRecorder receives the same events inline and is intended for fast, concurrency-safe metrics recorders. Prometheus support lives in contrib/prometheus; OpenTelemetry job tracing lives in contrib/otel.

Packages

Package Purpose
cron Scheduler, parser, lifecycle, events
cron/workflow Typed bounded DAG executor
cron/wrap Job wrappers
cron/parserext Quartz day tokens
cron/coordination/redis Redis claimer and elector
cron/coordination/postgres PostgreSQL claimer and elector
cron/contrib/prometheus Prometheus recorder
cron/contrib/otel OpenTelemetry wrapper

API details and examples are on pkg.go.dev.

Documentation

Overview

Package cron schedules context-aware jobs from cron expressions or Schedule implementations. Stop cancels running jobs; Drain waits without canceling.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrCapacityReached     = errors.New("cron: capacity reached")
	ErrAlreadyRunning      = errors.New("cron: job already running")
	ErrJobTimeout          = errors.New("cron: job timeout")
	ErrCronStopping        = errors.New("cron: scheduler stopping")
	ErrEntryNotFound       = errors.New("cron: entry not found")
	ErrSchedulerNotRunning = errors.New("cron: scheduler not running")
	ErrConcurrencyLimit    = errors.New("cron: max concurrent reached")
	ErrSchedulerStopped    = errors.New("cron: scheduler stopped")
	ErrNilJob              = errors.New("cron: nil job")
	ErrNilSchedule         = errors.New("cron: nil schedule")
	ErrJobPanic            = errors.New("cron: job panicked")
	ErrClaimerRequiresKey  = errors.New("cron: distributed claimer requires WithKey")
	ErrDuplicateKey        = errors.New("cron: duplicate entry key")
	ErrNilContext          = errors.New("cron: nil context")
	ErrInvalidOption       = errors.New("cron: invalid option")
)

Errors returned by scheduler configuration, lifecycle, and dispatch.

Functions

func Between

func Between(s Schedule, start, end time.Time) iter.Seq[time.Time]

Between lazily yields every firing in (start, end].

func IsTriggered

func IsTriggered(s Schedule) bool

IsTriggered reports whether s came from TriggeredSchedule.

func NextN

func NextN(s Schedule, from time.Time, n int) []time.Time

NextN returns the next n firings strictly after from.

func ValidateSpec

func ValidateSpec(spec string) error

ValidateSpec checks spec with the standard parser.

func ValidateSpecWith

func ValidateSpecWith(spec string, p Parser) error

ValidateSpecWith checks spec with p.

Types

type AlignedDelay added in v0.5.1

type AlignedDelay time.Duration

AlignedDelay is an epoch-aligned interval for replicas that must compute the same fire times. Non-positive intervals never fire.

func (AlignedDelay) Next added in v0.5.1

func (d AlignedDelay) Next(now time.Time) time.Time

func (AlignedDelay) String added in v0.5.1

func (d AlignedDelay) String() string

type CanceledFireEvent added in v0.5.3

type CanceledFireEvent struct {
	Entry       EntryRef
	ScheduledAt time.Time
	Cause       error
}

CanceledFireEvent reports a reserved fire canceled before job execution, such as a scheduler shutdown during jitter.

type Claimer added in v0.5.3

type Claimer interface {
	Claim(ctx context.Context, fireKey string) (bool, error)
}

Claimer lets one scheduler instance claim a fire. false, nil means another instance already claimed it; a non-nil error is a backend failure. Claims must remain reserved long enough that a delayed replica cannot run the same fire later. Implementations own their timeout and retention policy.

type ConstantDelay

type ConstantDelay time.Duration

ConstantDelay is a process-anchored interval with a one-second floor. Whole-second intervals align to second boundaries.

func (ConstantDelay) Next

func (d ConstantDelay) Next(now time.Time) time.Time

func (ConstantDelay) String

func (d ConstantDelay) String() string

type Cron

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

Cron is a job scheduler. Construct one with New, register jobs, then Start.

func MustNew added in v0.5.3

func MustNew(opts ...Option) *Cron

MustNew constructs a Cron and panics if an option is invalid.

func New

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

New constructs a Cron. It does not start scheduling until Start is called.

func (*Cron) Add

func (c *Cron) Add(spec string, j Job, opts ...EntryOption) (EntryID, error)

Add parses spec and registers j. It returns a *ParseError for invalid specs or ErrCapacityReached when WithMaxEntries rejects the registration.

func (*Cron) AddSchedule

func (c *Cron) AddSchedule(s Schedule, j Job, opts ...EntryOption) (EntryID, error)

AddSchedule registers j against a programmatic Schedule.

func (*Cron) Drain added in v0.3.0

func (c *Cron) Drain(ctx context.Context) error

Drain is Stop without cancelling in-flight jobs: it stops scheduling new fires and waits for running jobs to finish naturally, capped by ctx.

func (*Cron) Entries

func (c *Cron) Entries() iter.Seq[Entry]

Entries returns registered entry snapshots ordered by Next.

func (*Cron) Entry

func (c *Cron) Entry(id EntryID) (Entry, bool)

Entry returns the current snapshot for id.

func (*Cron) Pause added in v0.3.0

func (c *Cron) Pause(id EntryID) bool

Pause suspends automatic fires for id, keeping the entry and its Prev. Manual Trigger still works while paused. Returns false if id is unknown.

func (*Cron) Remove

func (c *Cron) Remove(id EntryID) bool

Remove deregisters id. In-flight invocations continue; future automatic fires and future Trigger calls for id are rejected.

func (*Cron) Resume added in v0.3.0

func (c *Cron) Resume(id EntryID) bool

Resume re-enables automatic fires for id, scheduling from now. Returns false if id is unknown.

func (*Cron) Running

func (c *Cron) Running() bool

Running reports whether the scheduler is running. It is observational; use Trigger's returned error for race-free dispatch decisions.

func (*Cron) Start

func (c *Cron) Start() error

Start launches the scheduler. It is idempotent while running and returns ErrSchedulerStopped after Stop has been called.

func (*Cron) Stop

func (c *Cron) Stop(ctx context.Context) error

Stop halts the scheduler, cancels in-flight jobs (ErrCronStopping as the cause), and waits for the loop, jobs, and observer queue to drain, capped by ctx. Returns ctx.Err() on timeout. Do not call it from inside a Job.

func (*Cron) Trigger

func (c *Cron) Trigger(id EntryID) error

Trigger fires id immediately, bypassing jitter. It returns ErrSchedulerNotRunning, ErrEntryNotFound, or ErrConcurrencyLimit when dispatch is rejected. Paused entries can still be triggered.

func (*Cron) TriggerAndWait added in v0.3.0

func (c *Cron) TriggerAndWait(ctx context.Context, id EntryID) error

TriggerAndWait fires id like Trigger and blocks until the invocation returns, yielding the job's error. ctx bounds only the wait; on ctx cancellation the job keeps running.

func (*Cron) TriggerByName

func (c *Cron) TriggerByName(name string) (int, error)

TriggerByName fires every entry whose Name matches name. Returns the successful dispatch count and errors.Join of per-Trigger failures. No match returns (0, nil); not running returns (0, ErrSchedulerNotRunning).

func (*Cron) Update added in v0.3.0

func (c *Cron) Update(id EntryID, spec string) error

Update re-parses spec and swaps id's schedule in place, keeping the job, entry options, ID, and Prev. The next fire is recomputed from now.

func (*Cron) UpdateSchedule added in v0.3.0

func (c *Cron) UpdateSchedule(id EntryID, s Schedule) error

UpdateSchedule is Update for a programmatic Schedule.

type Elector added in v0.3.0

type Elector interface {
	IsLeader(ctx context.Context) (bool, error)
}

Elector reports whether this instance currently leads. false, nil is the normal follower state; a non-nil error is a backend failure.

type Entry

type Entry struct {
	ID       EntryID
	Name     string
	Key      string // stable identity for distributed fire claims
	Spec     string // empty for AddSchedule entries
	Schedule Schedule
	Prev     time.Time // zero if never fired
	Next     time.Time // zero if exhausted, paused, or TriggeredSchedule
	Paused   bool
}

Entry is the public read-only view of a scheduled item. Safe to copy.

func (Entry) LogValue

func (e Entry) LogValue() slog.Value

func (Entry) Valid

func (e Entry) Valid() bool

Valid reports whether e has a non-zero entry ID.

type EntryID

type EntryID uint64

EntryID is an opaque, process-local identifier.

func (EntryID) LogValue

func (id EntryID) LogValue() slog.Value

func (EntryID) String

func (id EntryID) String() string

type EntryInfo added in v0.4.0

type EntryInfo struct {
	ID          EntryID
	Name        string
	Key         string
	ScheduledAt time.Time
}

EntryInfo identifies the running invocation inside a job's context.

func EntryInfoFromContext added in v0.4.0

func EntryInfoFromContext(ctx context.Context) (EntryInfo, bool)

EntryInfoFromContext returns the identity of the entry whose job is running under ctx. The scheduler injects it for every dispatch, so wrappers and jobs can tell which entry — and which fire — they serve.

type EntryOption

type EntryOption func(*entryConfig) error

EntryOption configures one entry.

func WithEntryChain

func WithEntryChain(wrappers ...Wrapper) EntryOption

WithEntryChain installs per-entry wrappers inside the global chain.

func WithEntryClaimer added in v0.5.3

func WithEntryClaimer(claimer Claimer) EntryOption

WithEntryClaimer overrides the scheduler's Claimer for one entry. An explicit nil disables distributed claims for the entry.

func WithEntryJitter added in v0.3.0

func WithEntryJitter(max time.Duration) EntryOption

WithEntryJitter overrides the scheduler's jitter for one entry. Zero disables jitter for the entry.

func WithEntryMissedFire added in v0.3.0

func WithEntryMissedFire(p MissedFirePolicy) EntryOption

WithEntryMissedFire overrides the scheduler's missed-fire policy for one entry.

func WithEntryRetry

func WithEntryRetry(p RetryPolicy) EntryOption

WithEntryRetry overrides the global retry for one entry. A zero policy disables retry for that entry.

func WithKey added in v0.5.3

func WithKey(key string) EntryOption

WithKey sets the stable, unique identity used for distributed fire claims. It is independent from the display-oriented Name.

func WithLastRun added in v0.3.0

func WithLastRun(t time.Time) EntryOption

WithLastRun seeds the entry's schedule anchor, usually the persisted time of the last run before a restart. The first fire is computed from t instead of now, so a missed-fire policy can catch up work missed while the process was down. It also seeds Entry.Prev.

func WithName

func WithName(name string) EntryOption

WithName labels an entry.

func WithTimeout

func WithTimeout(d time.Duration) EntryOption

WithTimeout caps a Job's runtime with ErrJobTimeout as the cancel cause.

type EntryRef added in v0.5.3

type EntryRef struct {
	ID   EntryID
	Key  string
	Name string
}

EntryRef identifies the entry associated with an event.

type Event added in v0.5.3

type Event interface {
	// contains filtered or unexported methods
}

Event is one scheduler event. Its concrete types are defined by this package, so consumers can use a type switch without accepting arbitrary implementations.

type Job

type Job interface {
	Run(ctx context.Context) error
}

Job is the unit of work executed by the scheduler.

type JobCompleteEvent added in v0.5.3

type JobCompleteEvent struct {
	Entry       EntryRef
	ScheduledAt time.Time
	StartedAt   time.Time
	Duration    time.Duration
	Err         error
}

JobCompleteEvent reports the result of a job wrapper chain.

type JobFunc

type JobFunc func(ctx context.Context) error

JobFunc adapts a function to Job.

Example
package main

import (
	"context"
	"fmt"

	"github.com/libtnb/cron"
)

func main() {
	j := cron.JobFunc(func(ctx context.Context) error {
		fmt.Println("hello")
		return nil
	})
	_ = j.Run(context.Background())
}
Output:
hello

func (JobFunc) Run

func (f JobFunc) Run(ctx context.Context) error

type JobStartEvent added in v0.5.3

type JobStartEvent struct {
	Entry       EntryRef
	ScheduledAt time.Time
	StartedAt   time.Time
}

JobStartEvent reports a job immediately before its wrapper chain runs.

type MissedFireEvent added in v0.5.3

type MissedFireEvent struct {
	Entry       EntryRef
	ScheduledAt time.Time
	Lateness    time.Duration
	Policy      MissedFirePolicy
}

MissedFireEvent reports a fire that was late enough to invoke the entry's missed-fire policy.

type MissedFirePolicy

type MissedFirePolicy uint8

MissedFirePolicy controls behaviour when a fire is later than WithMissedTolerance. MissedFireEvent is published regardless of policy.

const (
	// MissedSkip ignores missed firings and resumes from the next
	// scheduled time. This is the default.
	MissedSkip MissedFirePolicy = iota

	// MissedRunOnce runs the job once for the most recent missed firing
	// (latest schedule.Next <= now), then resumes normally.
	MissedRunOnce

	// MissedRunAll runs the job once per missed firing (newest
	// missedRunAllCap kept), then resumes normally.
	MissedRunAll
)

func (MissedFirePolicy) String

func (p MissedFirePolicy) String() string

type Observer added in v0.5.3

type Observer interface {
	Observe(Event)
}

Observer receives scheduler events asynchronously and in publication order. One slow observer can fill the shared queue; new events are then dropped.

type ObserverDropEvent added in v0.5.3

type ObserverDropEvent struct {
	Dropped int64
}

ObserverDropEvent reports that the async observer queue dropped an event. Dropped is the cumulative count for this Cron.

type ObserverFunc added in v0.5.3

type ObserverFunc func(Event)

ObserverFunc adapts a function to Observer.

func (ObserverFunc) Observe added in v0.5.3

func (f ObserverFunc) Observe(event Event)

type Option

type Option func(*config) error

Option configures a Cron.

func WithBaseContext added in v0.3.0

func WithBaseContext(ctx context.Context) Option

WithBaseContext sets the root context jobs inherit from. Cancelling it stops firing and cancels in-flight jobs, like Stop but without waiting.

func WithChain

func WithChain(wrappers ...Wrapper) Option

WithChain installs global wrappers. First wrapper is outermost.

func WithClaimer added in v0.5.3

func WithClaimer(claimer Claimer) Option

WithClaimer sets the distributed Claimer used for automatic fires. Manual Trigger bypasses coordination. Entries using it must configure WithKey.

func WithElector added in v0.3.0

func WithElector(e Elector) Option

WithElector gates automatic fires on leadership. Follower state and backend failure both skip the fire but produce distinct SkipReason values. Manual Trigger bypasses coordination.

func WithJitter

func WithJitter(max time.Duration) Option

WithJitter adds a random delay in [0, max) to each firing.

func WithLocation

func WithLocation(loc *time.Location) Option

WithLocation sets the default schedule timezone. Default is time.Local. Ignored when WithParser is set: a custom parser owns its timezone.

func WithLogger

func WithLogger(l *slog.Logger) Option

WithLogger sets the slog.Logger. Default slog.Default().

func WithMaxConcurrent

func WithMaxConcurrent(n int) Option

WithMaxConcurrent caps in-flight jobs. Zero means unlimited.

func WithMaxEntries

func WithMaxEntries(n int) Option

WithMaxEntries caps registered entries. Zero means unlimited.

func WithMissedFire

func WithMissedFire(p MissedFirePolicy) Option

WithMissedFire selects the missed-fire policy. Default MissedSkip.

func WithMissedTolerance

func WithMissedTolerance(d time.Duration) Option

WithMissedTolerance sets the lateness threshold for "missed". Default 1s.

func WithObserverBuffer added in v0.5.3

func WithObserverBuffer(n int) Option

WithObserverBuffer sets the async event queue capacity. Zero selects the default. A full queue drops new observer events while the Recorder still receives them.

func WithObservers added in v0.5.3

func WithObservers(observers ...Observer) Option

WithObservers installs async event observers. Events are serialized through one bounded queue and delivered to observers in option order.

func WithParser

func WithParser(p Parser) Option

WithParser installs a parser. It takes over timezone resolution, so WithLocation and WithSecondsField no longer apply.

func WithRecorder

func WithRecorder(r Recorder) Option

WithRecorder installs an inline event recorder. Record may be called concurrently and must be concurrency-safe and fast.

func WithRetry

func WithRetry(p RetryPolicy) Option

WithRetry sets the default RetryPolicy. Overridden by WithEntryRetry.

func WithSecondsField added in v0.2.2

func WithSecondsField() Option

WithSecondsField enables a leading seconds field in the built-in parser, so the common seconds + WithLocation case composes without WithParser.

func WithoutRecover added in v0.3.0

func WithoutRecover() Option

WithoutRecover disables the built-in job panic recovery. By default a panicking job is recovered into an ErrJobPanic-wrapped error; with this option the panic propagates and crashes the process.

type ParseError

type ParseError struct {
	Spec   string
	Field  string // e.g. "minute"; "" if not applicable
	Pos    int    // 0-based byte offset; -1 if unknown
	Reason string
	Err    error
}

ParseError describes a failure parsing a cron specification.

func (*ParseError) Error

func (e *ParseError) Error() string

func (*ParseError) Unwrap

func (e *ParseError) Unwrap() error

type Parser

type Parser interface {
	Parse(spec string) (Schedule, error)
}

Parser turns a textual spec into a Schedule. Cron caches parser results.

type ParserOption

type ParserOption func(*parserConfig)

ParserOption configures NewStandardParser.

func WithDefaultLocation

func WithDefaultLocation(loc *time.Location) ParserOption

WithDefaultLocation sets the default timezone for specs without TZ=/CRON_TZ=. nil means time.Local.

func WithOptionalSeconds added in v0.5.3

func WithOptionalSeconds() ParserOption

WithOptionalSeconds accepts both 5- and 6-field specs. A 5-field spec is parsed with second=0.

func WithParserExt

func WithParserExt(ext Parser) ParserOption

WithParserExt consults ext before the standard parser. Returning (nil, nil) falls through to standard parsing.

func WithRequiredSeconds added in v0.5.3

func WithRequiredSeconds() ParserOption

WithRequiredSeconds requires exactly 6 fields, including leading seconds.

type QueueDepthEvent added in v0.5.3

type QueueDepthEvent struct {
	Depth int
}

QueueDepthEvent reports the number of entries in the scheduling heap.

type Recorder added in v0.5.3

type Recorder interface {
	Record(Event)
}

Recorder receives scheduler events inline. Record may be called concurrently and must be concurrency-safe and fast. A panic is recovered and logged.

type RecorderFunc added in v0.5.3

type RecorderFunc func(Event)

RecorderFunc adapts a function to Recorder.

func (RecorderFunc) Record added in v0.5.3

func (f RecorderFunc) Record(event Event)

type RejectReason added in v0.5.3

type RejectReason uint8

RejectReason classifies a fire rejected before job execution.

const (
	RejectUnknown RejectReason = iota
	RejectConcurrencyLimit
)

func (RejectReason) String added in v0.5.3

func (r RejectReason) String() string

type RejectedFireEvent added in v0.5.3

type RejectedFireEvent struct {
	Entry       EntryRef
	ScheduledAt time.Time
	Reason      RejectReason
}

RejectedFireEvent reports a fire rejected before job execution.

type RetryOption

type RetryOption func(*RetryPolicy)

RetryOption configures a RetryPolicy built by Retry.

func RetryInitial

func RetryInitial(d time.Duration) RetryOption

RetryInitial sets the first retry delay (default 1s).

func RetryJitterFrac

func RetryJitterFrac(f float64) RetryOption

RetryJitterFrac is fractional uniform jitter (e.g. 0.1 = ±10%).

func RetryMaxDelay

func RetryMaxDelay(d time.Duration) RetryOption

RetryMaxDelay caps backoff (zero = uncapped).

func RetryMultiplier

func RetryMultiplier(m float64) RetryOption

RetryMultiplier is the per-attempt growth factor (<=1 stays constant).

type RetryPolicy

type RetryPolicy struct {
	MaxRetries int
	Initial    time.Duration
	MaxDelay   time.Duration
	Multiplier float64
	JitterFrac float64
}

RetryPolicy describes exponential backoff with optional jitter. MaxRetries == 0 disables retry; negative means unlimited until ctx cancellation. Fields are exported for config-driven assembly; use Retry(...) for programmatic construction.

func Retry

func Retry(maxRetries int, opts ...RetryOption) RetryPolicy

Retry builds a RetryPolicy. maxRetries is the number of retries after the initial attempt; negative retries until ctx cancellation.

func (RetryPolicy) IsZero

func (p RetryPolicy) IsZero() bool

IsZero is keyed only on MaxRetries so half-filled policies (e.g. only Initial set) don't produce a useless wrapper.

func (RetryPolicy) Wrapper

func (p RetryPolicy) Wrapper() Wrapper

Wrapper returns a Wrapper that retries on error per p. Attempt errors are joined via errors.Join; ctx cancellation aborts, recording context.Cause so ErrJobTimeout / ErrCronStopping survive into the joined error.

type Schedule

type Schedule interface {
	Next(now time.Time) time.Time
}

Schedule yields successive firing times. Next must return the first firing strictly after now, or zero when exhausted.

func Filter added in v0.3.0

func Filter(s Schedule, keep func(time.Time) bool) Schedule

Filter wraps s, skipping firings for which keep returns false — e.g. a holiday calendar. A nil keep passes everything through. The search gives up (returns zero) after filterScanCap consecutive rejections.

func OnceAt added in v0.3.0

func OnceAt(t time.Time) Schedule

OnceAt fires exactly once, at t. If t is already past, it never fires.

func TriggeredSchedule

func TriggeredSchedule() Schedule

TriggeredSchedule never fires automatically. Combine with Trigger.

func Union added in v0.3.0

func Union(schedules ...Schedule) Schedule

Union fires whenever any of the schedules fires. Nil members are ignored; an empty union never fires.

type ScheduleEvent added in v0.5.3

type ScheduleEvent struct {
	Entry    EntryRef
	Schedule Schedule
	Next     time.Time
}

ScheduleEvent reports an entry's newly computed next fire. Next is zero when the schedule has no future fire.

type SkipReason added in v0.3.0

type SkipReason uint8

SkipReason classifies why distributed coordination suppressed a fire.

const (
	SkipUnknown SkipReason = iota
	SkipNotLeader
	SkipElectionError
	SkipAlreadyClaimed
	SkipClaimError
)

func (SkipReason) String added in v0.3.0

func (r SkipReason) String() string

type SkippedFireEvent added in v0.5.3

type SkippedFireEvent struct {
	Entry       EntryRef
	ScheduledAt time.Time
	Reason      SkipReason
	Err         error
}

SkippedFireEvent reports a fire suppressed by distributed coordination. Err is non-nil only when the coordination backend failed.

type SpecAnalysis

type SpecAnalysis struct {
	Spec        string
	Valid       bool
	Err         error
	IsTriggered bool
	Descriptor  string         // "@every", "@hourly", ... or "" for 5/6-field specs
	Interval    time.Duration  // set when Descriptor == "@every"
	Location    *time.Location // schedule timezone
	NextRun     time.Time      // upcoming firing relative to the now passed in
}

SpecAnalysis is the result of AnalyzeSpec. Most fields are populated only when Valid is true.

func AnalyzeSpec

func AnalyzeSpec(spec string, now time.Time) SpecAnalysis

AnalyzeSpec describes spec relative to now using the standard parser.

func AnalyzeSpecWith

func AnalyzeSpecWith(spec string, p Parser, now time.Time) SpecAnalysis

AnalyzeSpecWith describes spec relative to now using p.

type SpecSchedule

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

SpecSchedule is a parsed cron expression.

func (*SpecSchedule) Location

func (s *SpecSchedule) Location() *time.Location

Location returns the evaluation timezone.

func (*SpecSchedule) LogValue

func (s *SpecSchedule) LogValue() slog.Value

func (*SpecSchedule) Next

func (s *SpecSchedule) Next(t time.Time) time.Time

Next returns the next firing after t, or zero if none is found.

The hour branch reconstructs the wall clock at the target hour instead of adding an absolute (h-hour)*time.Hour, which would overshoot a DST spring-forward gap and skip the day. The minute/second branches keep their absolute jumps: they never straddle a whole-hour DST boundary, and stepping through the repeated hour on fall-back keeps both firings observable.

func (*SpecSchedule) Upcoming

func (s *SpecSchedule) Upcoming(from time.Time) iter.Seq[time.Time]

Upcoming is a lazy iterator over future firings.

type StandardParser

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

StandardParser is safe for concurrent use after construction.

func NewStandardParser

func NewStandardParser(opts ...ParserOption) *StandardParser

NewStandardParser handles 5/6-field specs, descriptors, and TZ prefixes.

func (*StandardParser) Parse

func (p *StandardParser) Parse(spec string) (Schedule, error)

type Upcoming

type Upcoming interface {
	Upcoming(from time.Time) iter.Seq[time.Time]
}

Upcoming is an optional lazy iteration capability.

type Wrapper

type Wrapper func(Job) Job

Wrapper decorates a Job.

func Chain

func Chain(wrappers ...Wrapper) Wrapper

Chain composes wrappers so the first wraps outermost.

Example
package main

import (
	"context"
	"fmt"

	"github.com/libtnb/cron"
)

func main() {
	mk := func(name string) cron.Wrapper {
		return func(j cron.Job) cron.Job {
			return cron.JobFunc(func(ctx context.Context) error {
				fmt.Println("enter", name)
				err := j.Run(ctx)
				fmt.Println("leave", name)
				return err
			})
		}
	}
	core := cron.JobFunc(func(ctx context.Context) error {
		fmt.Println("run core")
		return nil
	})
	_ = cron.Chain(mk("outer"), mk("inner"))(core).Run(context.Background())
}
Output:
enter outer
enter inner
run core
leave inner
leave outer

Directories

Path Synopsis
_examples
hello command
quartz command
seconds command
slog command
workflow command
contrib
otel module
prometheus module
coordination
postgres module
redis module
internal
bitmask
Package bitmask provides bit-set scans shared by the schedule implementations.
Package bitmask provides bit-set scans shared by the schedule implementations.
heap
Package heap provides a typed min-heap with addressable items.
Package heap provides a typed min-heap with addressable items.
parsecache
Package parsecache memoises parser results.
Package parsecache memoises parser results.
Package parserext provides optional cron parser extensions.
Package parserext provides optional cron parser extensions.
Package workflow builds typed DAGs of cron jobs.
Package workflow builds typed DAGs of cron jobs.
Package wrap supplies Job decorators.
Package wrap supplies Job decorators.

Jump to

Keyboard shortcuts

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