go.bigb.es/auxilia
Documentation
Index
- type ChronosContext
- type Clock
- type Job
- func MustCron(spec string, fn JobFunc) *Job
- func MustEvery(fn JobFunc, every ...Span) *Job
- func NewCron(spec string, fn JobFunc) *Job
- func NewEvery(fn JobFunc, every ...Span) *Job
- func (*Job) Delta(d time.Duration) *Job
- func (*Job) Name(name string) *Job
- func (*Job) OnOverlap(p OverlapPolicy) *Job
- func (*Job) SlotWait(d time.Duration) *Job
- func (*Job) Timeout(d time.Duration) *Job
- type JobFunc
- type Option
- type OverlapPolicy
- type Schedule
- type Span
- type Supervisor
- type Timer
Variables
var ( Nanosecond = Span{Dur: time.Nanosecond} Microsecond = Span{Dur: time.Microsecond} Millisecond = Span{Dur: time.Millisecond} Second = Span{Dur: time.Second} Minute = Span{Dur: time.Minute} Hour = Span{Dur: time.Hour} Day = Span{Days: 1} Week = Span{Days: 7} Month = Span{Months: 1} Year = Span{Years: 1} )
Unit spans. Sub-day units live in Dur; Day and Week are calendar days; Month and Year are calendar units resolved by time.Time.AddDate.
Types
type ChronosContext struct { context.Context // the per-run context; promotes Deadline/Done/Err/Value (IV11) // contains filtered or unexported fields }
ChronosContext is the handle a JobFunc receives on each run. It embeds the per-run context.Context so Deadline/Done/Err/Value reflect the run's cancellation (IV11), and offers methods to log, register sibling jobs, and deactivate jobs at runtime.
func (c *ChronosContext) Add(j *Job) error
Add registers a new Job with the running supervisor, surfacing any stashed build error (IV6).
func (c *ChronosContext) Deactivate()
Deactivate retires the running job (by name), stopping its further fires without cancelling this run (IV13).
func (c *ChronosContext) DeactivateJob(n string) bool
DeactivateJob retires the named job, reporting whether it existed.
func (c *ChronosContext) Logger() *slog.Logger
Logger returns the supervisor's logger.
func (c *ChronosContext) Name() string
Name returns the running job's name.
type Clock interface { // Now returns the current time. Now() time.Time // NewTimer returns a [Timer] that fires once after d. NewTimer(d time.Duration) Timer }
Clock is the injectable-time seam: it provides the current time and creates timers, so callers can substitute a fake clock in tests.
type Job struct { // contains filtered or unexported fields }
Job is a schedule paired with the function to run and per-job options. Construct one with NewCron or NewEvery, then refine it with the chained builders (Job.Delta, Job.Timeout, etc.).
Construction errors are stashed in buildErr rather than panicked (IV6); they surface when the job is registered. The Must* variants panic instead. The paired *Set bools record whether Job.Timeout and Job.SlotWait were called, so the supervisor can tell an explicit zero from "unset" (GPC1).
MustCron is NewCron that panics on a malformed spec.
MustEvery is NewEvery that panics on an empty or all-zero span.
NewEvery builds a Job that fires every total of the given spans. The spans are summed component-wise (AS1); a non-positive total (empty, all-zero, or any negative component) is rejected via buildErr (IV6), since [everySchedule] requires a forward-moving span to honour the strictly-after contract (IV1).
func (j *Job) Delta(d time.Duration) *Job
Delta offsets each fire by d relative to the schedule's nominal time.
Name sets the job's name, used for logging and self-deactivation.
func (j *Job) OnOverlap(p OverlapPolicy) *Job
OnOverlap sets the OverlapPolicy applied when a fire arrives during a still-running prior invocation.
func (j *Job) SlotWait(d time.Duration) *Job
SlotWait bounds how long a fire waits for an in-flight run before the overlap policy applies. Calling it marks slotWait as explicitly set.
func (j *Job) Timeout(d time.Duration) *Job
Timeout caps each run at d; the run's ChronosContext is cancelled when it elapses. Calling it marks the timeout as explicitly set (GPC1).
type JobFunc func(cc *ChronosContext) error
JobFunc is the work a Job runs on each fire. It receives a ChronosContext scoped to the run (cancelled on timeout or shutdown) and returns an error that the supervisor records.
type Option func(*supervisorOpts)
Option configures a Supervisor at construction time.
WithClock injects a Clock, chiefly for deterministic tests. The default is the package wall clock.
func WithJitter(fn func(max time.Duration) time.Duration) Option
WithJitter injects the source of per-fire jitter spread (PC3): given a job's Job.Delta, it returns the offset added to that fire, expected in [0, max). The default draws uniformly from math/rand/v2. Chiefly for deterministic tests.
func WithLocation(loc *time.Location) Option
WithLocation sets the time zone schedules are evaluated in (AS2). The default is time.Local.
func WithLogger(l *slog.Logger) Option
WithLogger sets the logger used for all supervisor logging (PC4). The default is slog.Default.
func WithMaxInflight(n int) Option
WithMaxInflight bounds the number of runs executing concurrently across all jobs (IV9). n<=0 is unlimited.
func WithSlotWait(d time.Duration) Option
WithSlotWait sets the default slot-wait applied to jobs that do not set their own with Job.SlotWait (IV10): 0 sheds when full, <0 waits indefinitely, >0 waits up to the duration.
func WithTimeout(d time.Duration) Option
WithTimeout sets the default per-run timeout applied to jobs that do not set their own with Job.Timeout. Zero means no timeout.
type OverlapPolicy int
OverlapPolicy decides what happens when a Job's fire time arrives while its previous run is still in flight.
const ( // OverlapSkip drops the new fire when the prior run is still active. OverlapSkip OverlapPolicy = iota // OverlapAllow starts the new run concurrently with the prior one. OverlapAllow )
type Schedule interface { // Next returns the next fire time strictly after the given time, or // the zero [time.Time] to mean "no further runs". The argument is // the anchor; for a recurring schedule it is typically the time of // the previous fire (or loop start for the first call). Next(after time.Time) time.Time }
Schedule computes fire times. It is the single scheduling seam: it never sleeps and has no side effects.
type Span struct { Years int Months int Days int Dur time.Duration }
Span is a calendar-aware amount of time. Calendar components (Years, Months, Days) are added via time.Time.AddDate, which makes them sensitive to month lengths, leap years, and daylight saving; the sub-day Dur is added as an absolute time.Duration.
Minutes returns a Span of n minutes of absolute duration.
Seconds returns a Span of n seconds of absolute duration.
func (s Span) IsZero() bool
IsZero reports whether s has no calendar and no duration component.
type Supervisor struct { // contains filtered or unexported fields }
Supervisor owns a set of [Job]s and runs each on its own scheduling loop. It bounds total concurrency with a shared semaphore (IV9), drains in-flight runs on Supervisor.Stop (IV5), and never blocks a loop on a run, slot acquisition, or timeout (IV3). The zero value is not usable; construct one with New.
func New(opts ...Option) *Supervisor
New builds a Supervisor from the given [Option]s. Defaults: location time.Local, logger slog.Default, the package wall Clock, no timeout, unlimited concurrency, and slot-wait 0 (shed when full).
func (s *Supervisor) Add(j *Job) error
Add registers a Job, surfacing its stashed build error (IV6) and rejecting duplicate names. If the supervisor is already running, the job's loop starts immediately (IV12).
func (s *Supervisor) Deactivate(name string) bool
Deactivate retires the named job, stopping its future fires without cancelling any in-flight run (IV13). It reports whether the job existed and is idempotent.
func (s *Supervisor) Jobs() []string
Jobs returns the names of the registered jobs, sorted.
func (s *Supervisor) Start(ctx context.Context) error
Start begins scheduling every registered job, deriving the run root from ctx (PC2). It errors if already started.
func (s *Supervisor) Stop(ctx context.Context) error
Stop cancels every loop and run, then waits for in-flight runs to drain, bounded by ctx (IV5, PC2). It is idempotent and returns ctx.Err() if the drain outlasts ctx.
type Timer interface { // C returns the channel on which the fire time is delivered. C() <-chan time.Time // Stop prevents the timer from firing. It reports whether the call // stops the timer (false if it has already fired or been stopped). Stop() bool }
Timer is a single-shot timer created by a Clock.
Package chronos is an in-process, cron-like scheduler. It exists to run recurring work inside a single Go program without an external scheduler or a separate process: jobs share one supervisor, one concurrency budget, and the program's own context for shutdown.
A job pairs a schedule with a JobFunc. Build one of two ways:
Refine a job with chained builders before registering it: Job.Delta (per-fire jitter), Job.Timeout (cancel a slow run), Job.SlotWait (how long to wait for a concurrency slot), Job.Name, and Job.OnOverlap (OverlapSkip or OverlapAllow).
A Supervisor owns the jobs and their lifecycle. Build it with New and [Option]s, register jobs with Supervisor.Add, then call Supervisor.Start with a context and Supervisor.Stop to drain. The supervisor bounds total concurrency across all jobs with WithMaxInflight: when the budget is full, WithSlotWait (or the per-job Job.SlotWait) decides whether a fire sheds, waits, or waits then sheds.
Inside a run, the JobFunc receives a ChronosContext. It embeds the run's context.Context (cancelled on timeout or shutdown) and lets the job register sibling jobs with ChronosContext.Add or retire itself with ChronosContext.Deactivate without cancelling the current run.