Documentation
¶
Overview ¶
Package schedule persists cron jobs that fire an adh command on a cadence and fires the ones that are due (SPEC-ADDITIONS §15, §18). A job names a command (e.g. `sleep run`, `loop run dep-scan`) and a cron expression; `tick` runs every due job, records its outcome, and advances its next fire time. The store is SQLite so a schedule survives across the stateless-per-invocation CLI; time enters as a parameter so the disposition is deterministic and testable.
Index ¶
- Constants
- Variables
- func NextFire(expr string, now time.Time) time.Time
- func NextSleep(next, now time.Time, poll time.Duration) time.Duration
- func ParseCron(expr string) (cron.Schedule, error)
- type Fired
- type Job
- type JobSpec
- type RunStatus
- type Runner
- type Store
- func (s *Store) Add(ctx context.Context, spec JobSpec, now time.Time) (Job, error)
- func (s *Store) AdvanceNextFire(ctx context.Context, name string, next time.Time) error
- func (s *Store) Close() error
- func (s *Store) Due(ctx context.Context, now time.Time) ([]Job, error)
- func (s *Store) List(ctx context.Context) ([]Job, error)
- func (s *Store) MarkRan(ctx context.Context, name string, status RunStatus, at time.Time) error
- func (s *Store) Remove(ctx context.Context, name string) error
- func (s *Store) SoonestDeadline(ctx context.Context, now time.Time) (time.Time, error)
Constants ¶
const DefaultDBFile = "schedule.db"
DefaultDBFile is the schedule database, kept beside the rest of the .adh state.
Variables ¶
var ( // ErrNotFound means a named job does not exist. ErrNotFound = errors.New("schedule: job not found") // ErrConflict means a job with that name already exists. ErrConflict = errors.New("schedule: job already exists") // ErrInvalidCron means a cron expression was not accepted. ErrInvalidCron = errors.New("schedule: invalid cron expression") // ErrInvalidSpec means a job spec violates a creation invariant. ErrInvalidSpec = errors.New("schedule: invalid job spec") )
Sentinel errors are part of the package contract; callers branch with errors.Is and command shells map them to exit codes.
Functions ¶
func NextFire ¶
NextFire returns the next time the cron expression fires after now, or the zero time when the expression does not parse (a stored job with a bad expression simply never fires again rather than erroring the whole tick).
func NextSleep ¶
NextSleep is how long a daemon should sleep after a tick: until the earlier of the next deadline and the poll cap, floored above zero. The poll cap bounds how long an out-of-band add or remove goes unnoticed (there is no wake channel); a zero next (nothing scheduled) sleeps the full cap. It is pure so the loop's timing is tested without a clock.
Types ¶
type Fired ¶
Fired records one job the tick ran and its outcome.
func Tick ¶
Tick runs every job due at now: it executes the command, records the outcome, and advances the job's next fire to the next cron instant after now. One job's failure marks it failed and does not stop the others — the tick reports every job it fired. A store write failure (recording the outcome) is returned, since it means the schedule state is no longer trustworthy.
type Job ¶
type Job struct {
Name string `json:"name"`
Cron string `json:"cron"`
Command []string `json:"command"`
NextFire time.Time `json:"next_fire,omitzero"`
LastRun time.Time `json:"last_run,omitzero"`
LastStatus RunStatus `json:"last_status,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Job is a stored schedule entry: a named command fired on a cron cadence, with the denormalized outcome of its last run.
type JobSpec ¶
JobSpec is the user-supplied subset used to create a job; the store fills in the timestamps and the first NextFire.
type Runner ¶
Runner runs one job's command and reports whether it succeeded. A nil error is success (the command exited zero); any error — a non-zero exit or a failure to start — marks the run failed. It is the point-of-use seam: the sleep command supplies a runner that execs the adh binary; a test injects a fake.
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store persists schedule jobs in SQLite. It is the imperative shell; the cron disposition (ParseCron/NextFire) is the pure core the caller supplies results from. Concurrent callers against one database are serialized by SQLite's WAL and busy timeout.
func Open ¶
Open returns a Store backed by dir/schedule.db, creating dir and applying the schema. ctx scopes the schema apply, not the Store's lifetime; close with Close.
func (*Store) Add ¶
Add inserts a new job from spec, computing its first fire time from now. A name already in use is ErrConflict; an invalid spec is ErrInvalidSpec/ErrInvalidCron.
func (*Store) AdvanceNextFire ¶
AdvanceNextFire sets the job's next fire time; a zero next means it never fires again. A name that does not exist is ErrNotFound.
func (*Store) SoonestDeadline ¶
SoonestDeadline returns the earliest future fire time after now, or the zero time when nothing is scheduled. It is the seam a future blocking daemon sleeps on; the tick command does not use it.