scheduledtask

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Sep 9, 2026 License: Apache-2.0 Imports: 12 Imported by: 0

Documentation

Overview

Package scheduledtask execs an operator-defined command into a running app's container on a cron schedule (e.g. a nightly cleanup script, a periodic cache-warm job), mirroring internal/backup's own Runner/Scheduler split: Runner (this file) does one run and records its outcome, Scheduler (scheduler.go) decides when a run is due and calls Runner. The same Runner instance backs both the background cron loop and the "run now" HTTP trigger (internal/api), so there is exactly one place that actually execs a command and records what happened.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type AppStore

type AppStore interface {
	GetDesiredService(ctx context.Context, name string) (*store.DesiredService, error)
}

AppStore is the narrow store surface Runner needs to resolve a scheduled task's target service, the same "consumer defines its own narrow interface" convention internal/backup.ScheduleStore already establishes for this package's sibling.

type NodeRuntimeResolver

type NodeRuntimeResolver func(nodeID string) (docker.Runtime, error)

NodeRuntimeResolver resolves the docker.Runtime for a given node ID, identical in shape to internal/api's own NodeRuntimeResolver (router.go): both close over the same resolveNodeTransport helper in cmd/levelrail/main.go, redeclared here rather than imported across the package boundary, the same reasoning backup.ScheduledBackupRunner's own doc comment gives for its own redeclared interfaces.

type RunStore

type RunStore interface {
	RecordScheduledTaskRun(ctx context.Context, id string, ranAt time.Time, status, output string) error
}

RunStore is the store surface Runner needs to persist a run's outcome back onto the task's own row (RecordScheduledTaskRun, internal/store/scheduled_task.go).

type Runner

type Runner struct {
	Apps     AppStore
	Runs     RunStore
	Resolver NodeRuntimeResolver
	Logger   *slog.Logger

	// Now returns the current time, the same testable-clock field
	// backup.Runner.Now and backup.Scheduler.Now already establish:
	// production code leaves it nil (falls back to time.Now), tests set
	// it for deterministic timestamps.
	Now func() time.Time

	// Timeout overrides defaultRunTimeout when positive; zero (the
	// production default) falls back to it. Exists purely so a test can
	// exercise the timeout branch in milliseconds instead of actually
	// waiting defaultRunTimeout out.
	Timeout time.Duration
}

Runner execs one scheduled task's command into its target service's currently running container and records the outcome. Used both by Scheduler (a due cron tick) and by the "run now" HTTP handler (internal/api): both need the identical exec-and-record behavior, not two independent copies of it.

func (*Runner) Run

func (r *Runner) Run(ctx context.Context, task store.ScheduledTask) error

Run execs task.Command inside task.ServiceName's currently running container and records the outcome (RecordScheduledTaskRun): success, a nonzero exit ("failed"), a timeout, or the container simply not being up right now ("container_not_running"). The returned error is only ever a genuine infrastructure failure this call itself hit (loading the app, or recording the result once a command has already run): a command that ran but failed, or a container that wasn't running, are both normal, expected outcomes recorded on the task's own row, never returned as an error, the same "a nonzero exit is a 200, not a failure" distinction execResponse's own doc comment draws for the one-off HTTP exec path.

type ScheduleStore

type ScheduleStore interface {
	ListEnabledScheduledTasks(ctx context.Context) ([]store.ScheduledTask, error)
}

ScheduleStore is the narrow store surface Scheduler needs: every currently enabled scheduled task, re-derived fresh on every tick, the same shape internal/backup.ScheduleStore's own doc comment establishes for its sibling. *store.DB satisfies this structurally.

type Scheduler

type Scheduler struct {
	Store  ScheduleStore
	Runner TaskRunner
	Logger *slog.Logger
	// Now returns the current time; nil falls back to time.Now, the same
	// testable-clock convention backup.Scheduler.Now establishes.
	Now func() time.Time
	// contains filtered or unexported fields
}

Scheduler periodically checks which scheduled tasks have a due cron schedule and runs them through Runner, mirroring internal/backup.Scheduler's own shape field for field: same armed- before-running nextRun bookkeeping, same missed-schedule gap (a schedule that should have fired while the control plane was down waits for its next natural occurrence rather than catching up), same per-task error collection so one broken task never blocks the rest of a tick. See that type's own doc comment for the full reasoning; it applies here unchanged, just for scheduled tasks instead of scheduled backups.

func NewScheduler

func NewScheduler(store ScheduleStore, runner TaskRunner, logger *slog.Logger) *Scheduler

NewScheduler builds a Scheduler ready to Tick or Run. logger defaults to slog.Default() if nil, matching backup.NewScheduler's own convention.

func (*Scheduler) Run

func (s *Scheduler) Run(ctx context.Context, interval time.Duration) error

Run calls Tick on interval until ctx is done, matching the shape of every other periodic loop in this codebase (backup.Scheduler.Run, alerting.Engine.Run, telemetry.Collector.Run).

func (*Scheduler) Tick

func (s *Scheduler) Tick(ctx context.Context) error

Tick evaluates every currently enabled scheduled task once. Errors from an individual task (an invalid cron string, Runner.Run itself failing) are collected and joined, never stopping evaluation of the remaining tasks, the same "one broken resource must not block the rest" principle backup.Scheduler.Tick's own doc comment traces back to alerting.Engine.Tick.

type TaskRunner

type TaskRunner interface {
	Run(ctx context.Context, task store.ScheduledTask) error
}

TaskRunner is the surface Scheduler needs to actually run a task once its schedule comes due. *Runner satisfies this structurally; redeclared here rather than depended on directly so a test can substitute a fake without constructing a real Runner, the same reasoning backup.ScheduledBackupRunner's own doc comment gives.

Jump to

Keyboard shortcuts

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