scheduler

package module
v0.4.1 Latest Latest
Warning

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

Go to latest
Published: Jul 10, 2026 License: Apache-2.0 Imports: 21 Imported by: 0

Documentation

Overview

Package scheduler provides a config-driven cron/interval job scheduler as a lakta AsyncModule, wrapping go-co-op/gocron v2 with code-owned handlers, otel spans, panic recovery, overlap policies, per-job timezone/jitter and hot-reload.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Config

type Config struct {
	// Instance name; DefaultInstanceName by default.
	Name string `koanf:"-"`

	// Timezone is the scheduler-wide default location (IANA name). Per-job
	// JobSpec.Timezone overrides it. Defaults to "UTC".
	Timezone string `koanf:"timezone"`

	// Jobs holds config-declared job overlays. Prefer snake_case names;
	// hyphens cannot be overridden via environment variables.
	Jobs map[string]JobSpec `koanf:"jobs"`

	// CodeJobs holds jobs registered via WithJob (code-only). A config entry
	// with the same name overlays it field-by-field (config wins per field);
	// the Handler always persists.
	CodeJobs map[string]JobSpec `code_only:"WithJob" koanf:"-"`
}

Config is the worker-scheduler module config. Mirrors pool.Config: a config map (Jobs) overlays a code-only map (CodeJobs) by name via MergedJobs.

func NewConfig

func NewConfig(options ...Option) Config

NewConfig returns configuration with provided options based on defaults.

func NewDefaultConfig

func NewDefaultConfig() Config

NewDefaultConfig returns default configuration.

func (*Config) LoadFromKoanf

func (c *Config) LoadFromKoanf(k *koanf.Koanf, path string) error

LoadFromKoanf loads configuration from koanf instance at the given path.

func (*Config) MergedJobs

func (c *Config) MergedJobs() map[string]JobSpec

MergedJobs copies CodeJobs then overlays Jobs field-by-field per name; config wins per field while the code-owned Handler always persists (config never carries a func).

type JobInfo

type JobInfo struct {
	Name     string
	Schedule string
	Timezone string
	Enabled  bool
	NextRun  time.Time
	LastRun  time.Time
}

JobInfo is the flat, gocron-free introspection record the actuator reads via Scheduler.Jobs. No gocron types leak.

type JobSpec

type JobSpec struct {
	Schedule string        `koanf:"schedule"` // 6-field cron (seconds) or "@every 5m"
	Timezone string        `koanf:"timezone"` // per-job override of Config.Timezone; "" inherits
	Jitter   time.Duration `koanf:"jitter"`   // 0 = none
	Overlap  OverlapPolicy `koanf:"overlap"`  // "" defaults to OverlapSkip in translation

	// Enabled uses nil = true; false = never registered. This is the OPPOSITE
	// convention to the actuator's enabled:false default — here a job is on
	// unless a config entry explicitly disables it.
	Enabled *bool `koanf:"enabled"`

	// Handler runs per fire. koanf:"-" keeps config from ever carrying a func;
	// it survives hot-reload because config only overlays the other fields.
	Handler func(ctx context.Context) error `koanf:"-"`
}

JobSpec declares one scheduled job. Handler is code-owned (never from YAML); every other field is config-overridable by job name.

type Module

type Module struct {
	lakta.NamedBase
	// contains filtered or unexported fields
}

Module wires a Scheduler into DI as an AsyncModule.

func NewModule

func NewModule(options ...Option) *Module

NewModule creates a new worker-scheduler module.

func (*Module) ConfigPath

func (m *Module) ConfigPath() string

ConfigPath returns the koanf path for this module's configuration.

func (*Module) Dependencies

func (m *Module) Dependencies() ([]reflect.Type, []reflect.Type)

Dependencies declares the optional types this module needs from DI before Init. The otel module always provides a MeterProvider (noop when disabled), so declaring it orders otel before the scheduler; the tracer is resolved analogously and falls back to noop when otel is absent entirely.

func (*Module) Init

func (m *Module) Init(ctx context.Context) error

Init builds the gocron scheduler, registers every merged job, and provides the Scheduler to the injector so app modules can Register more jobs during their own Init (topo-sort guarantees scheduler inits first when declared a dep).

func (*Module) LoadConfig

func (m *Module) LoadConfig(k *koanf.Koanf) error

LoadConfig loads configuration from koanf.

func (*Module) OnReload

func (m *Module) OnReload(k *koanf.Koanf)

OnReload re-loads config then diffs MergedJobs against the live specs: added names get Registered, removed names get removed, and any name whose schedule/tz/jitter/overlap/enabled changed is re-Registered. Handlers are code-owned and persist across reload (config never carries a func).

func (*Module) Provides

func (m *Module) Provides() []reflect.Type

Provides returns the types this module registers in DI.

func (*Module) Shutdown

func (m *Module) Shutdown(ctx context.Context) error

Shutdown stops gocron (blocks until in-flight jobs finish) raced against ctx, mirroring pool.awaitClose: on the deadline it returns a wrapped ctx error.

func (*Module) StartAsync

func (m *Module) StartAsync(_ context.Context) error

StartAsync starts the gocron scheduler (non-blocking).

type Option

type Option func(m *Config)

Option configures the Module.

func WithJob

func WithJob(name, schedule string, fn func(ctx context.Context) error) Option

WithJob registers a code-owned job. Seeds CodeJobs[name] with Schedule + Handler; the remaining JobSpec fields keep their zero defaults and config may override them by the same name.

func WithName

func WithName(name string) Option

WithName sets the instance name for this module.

func WithTimezone

func WithTimezone(tz string) Option

WithTimezone sets the scheduler-wide default location (code-only; the config timezone key still wins on load).

type OverlapPolicy

type OverlapPolicy string

OverlapPolicy controls what happens when a job's previous run is still in flight at its next fire. Maps to a gocron singleton mode.

const (
	OverlapSkip  OverlapPolicy = "skip"  // drop the overlapping run (LimitModeReschedule)
	OverlapQueue OverlapPolicy = "queue" // serialize: run after the current one (LimitModeWait)
	OverlapAllow OverlapPolicy = "allow" // no singleton option; runs may overlap
)

type Scheduler

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

Scheduler wraps a gocron.Scheduler plus a name→job map, guarded by mu for concurrent Register/RunNow during hot-reload.

func (*Scheduler) Jobs

func (s *Scheduler) Jobs() []JobInfo

Jobs snapshots all live jobs as JobInfo for introspection, sorted by name.

func (*Scheduler) NextRun

func (s *Scheduler) NextRun(name string) (time.Time, error)

NextRun returns the next scheduled fire for name. Unknown name errors as above.

func (*Scheduler) Register

func (s *Scheduler) Register(name string, spec JobSpec) error

Register builds (or replaces) the gocron job for name from spec. A disabled spec (Enabled != nil && !*Enabled) or one with a nil Handler removes any existing job and returns nil without registering. Wraps spec.Handler via wrap before handing it to gocron.

func (*Scheduler) RunNow

func (s *Scheduler) RunNow(name string) error

RunNow fires the named job once, out of schedule. Unknown name returns an error listing the known job names.

Jump to

Keyboard shortcuts

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