cron

package
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: Mar 31, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Overview

Package cron provides a lightweight cron-like scheduler for agent jobs. It supports both the simple Roger crons.json format and the full OpenClaw jobs.json format (schedule.kind:"every", sessionTarget, wakeMode, delivery, payload model/timeout overrides, and state persistence).

Package cron — runlog.go implements persistent cron run logging (REQ-430).

After each cron job completes, a structured entry is appended to a per-job JSONL file at <agent>/cron/runs/<jobId>.jsonl. Supports paginated reads with filtering, sorting, and auto-pruning when files exceed 2MB / 2000 lines.

Index

Constants

View Source
const DefaultStaggerMs = 5 * 60 * 1000 // 5 minutes

DefaultStaggerMs is the default stagger window for intervals >= 1 hour.

Variables

View Source
var ErrJobNotFound = errors.New("job not found")

ErrJobNotFound is returned when a job ID does not match any known job.

Functions

func AppendRunLog

func AppendRunLog(logger *zap.SugaredLogger, dir string, entry RunLogEntry) error

AppendRunLog appends a single entry to the job's run log file.

func PruneIfNeeded

func PruneIfNeeded(path string, maxBytes int64, keepLines int) error

PruneIfNeeded trims a JSONL file to keepLines entries if it exceeds maxBytes.

Types

type Deliverer

type Deliverer = agentapi.Deliverer

Deliverer is an alias for agentapi.Deliverer.

type Delivery

type Delivery struct {
	Mode    string `json:"mode,omitempty"`    // "announce" or "none"
	Channel string `json:"channel,omitempty"` // "last" (currently only option)
}

Delivery defines how results are delivered. Mode: "announce" = send to all paired users; "none" = suppress delivery.

type Job

type Job struct {
	ID          string `json:"id"`
	Name        string `json:"name,omitempty"`
	Description string `json:"description,omitempty"`
	Enabled     bool   `json:"enabled"`

	// Legacy simple format fields (crons.json)
	Spec        string `json:"spec,omitempty"`        // @daily, @hourly, @every 1h, HH:MM
	Instruction string `json:"instruction,omitempty"` // text sent to agent
	SessionKey  string `json:"sessionKey,omitempty"`  // empty = "cron:<id>"

	// Full OpenClaw jobs.json fields
	CreatedAtMs int64     `json:"createdAtMs,omitempty"`
	UpdatedAtMs int64     `json:"updatedAtMs,omitempty"`
	Schedule    *Schedule `json:"schedule,omitempty"`

	// "isolated" = fresh session per run; "persistent" = reuse same key
	SessionTarget string `json:"sessionTarget,omitempty"`
	// "now" = run missed runs immediately on startup; "skip" = skip missed
	WakeMode string `json:"wakeMode,omitempty"`

	Payload      *Payload  `json:"payload,omitempty"`
	Delivery     *Delivery `json:"delivery,omitempty"`
	LightContext bool      `json:"lightContext,omitempty"` // if true, use minimal bootstrap context (HEARTBEAT.md only)
	State        *JobState `json:"state,omitempty"`
}

Job represents a scheduled agent task.

func (*Job) DisplayName

func (j *Job) DisplayName() string

DisplayName returns the best available name for display.

func (*Job) DisplaySchedule

func (j *Job) DisplaySchedule() string

DisplaySchedule returns a human-readable schedule string.

func (*Job) EffectiveInstruction

func (j *Job) EffectiveInstruction() string

EffectiveInstruction returns the message to send (supports both formats).

func (*Job) EffectiveInterval

func (j *Job) EffectiveInterval() (time.Duration, error)

EffectiveInterval returns the repeat interval (supports both formats).

func (*Job) EffectiveModel

func (j *Job) EffectiveModel() string

EffectiveModel returns the per-job model override, or "" if none.

func (*Job) EffectiveSessionKey

func (j *Job) EffectiveSessionKey() string

EffectiveSessionKey returns the session key for this run. isolated: fresh key per run; persistent: reuse "cron:<id>".

func (*Job) EffectiveTimeout

func (j *Job) EffectiveTimeout() time.Duration

EffectiveTimeout returns the per-job timeout, or 0 if none.

func (*Job) WantsDelivery

func (j *Job) WantsDelivery() bool

WantsDelivery returns true if the job wants results announced.

type JobState

type JobState struct {
	NextRunAtMs        int64  `json:"nextRunAtMs,omitempty"`
	LastRunAtMs        int64  `json:"lastRunAtMs,omitempty"`
	LastRunStatus      string `json:"lastRunStatus,omitempty"`
	LastStatus         string `json:"lastStatus,omitempty"`
	LastDurationMs     int64  `json:"lastDurationMs,omitempty"`
	LastDeliveryStatus string `json:"lastDeliveryStatus,omitempty"`
	ConsecutiveErrors  int    `json:"consecutiveErrors"`
	LastDelivered      bool   `json:"lastDelivered,omitempty"`
}

JobState tracks runtime state; persisted back to jobs.json.

type Manager

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

Manager schedules and manages cron jobs.

func New

func New(logger *zap.SugaredLogger, dir string, runFunc RunFunc) *Manager

New creates a Manager that stores state in dir/crons.json. runFunc is called for each job execution.

func (*Manager) Add

func (m *Manager) Add(spec, instruction string) (*Job, error)

Add creates a new enabled job (simple format). If Start() has already been called, the job is scheduled immediately.

func (*Manager) AddDeliverer

func (m *Manager) AddDeliverer(d Deliverer)

AddDeliverer registers a channel deliverer for job result delivery.

func (*Manager) Dir

func (m *Manager) Dir() string

Dir returns the state directory used for crons.json and run logs.

func (*Manager) List

func (m *Manager) List() []*Job

List returns a copy of all jobs.

func (*Manager) LoadJobsFile

func (m *Manager) LoadJobsFile(path string) error

LoadJobsFile loads the full-format jobs.json from the given path, merging into any already-loaded simple jobs (deduped by ID).

func (*Manager) Remove

func (m *Manager) Remove(id string) error

Remove deletes a job by ID.

func (*Manager) RunLogDir

func (m *Manager) RunLogDir() string

runLogDir returns the runs directory for this manager.

func (*Manager) RunNow

func (m *Manager) RunNow(ctx context.Context, id string) error

RunNow manually triggers a job by ID. Non-blocking.

func (*Manager) SetEnabled

func (m *Manager) SetEnabled(id string, enabled bool) error

SetEnabled enables or disables a job by ID. Re-enabling a job schedules it immediately if Start() has been called.

func (*Manager) Start

func (m *Manager) Start(ctx context.Context) error

Start begins the scheduling loop. It blocks until ctx is cancelled.

type Payload

type Payload struct {
	Kind           string `json:"kind"`                     // "agentTurn"
	Message        string `json:"message"`                  // instruction text
	Model          string `json:"model,omitempty"`          // per-job model override
	TimeoutSeconds int    `json:"timeoutSeconds,omitempty"` // per-job timeout
}

Payload defines what runs when the job fires.

type RunFunc

type RunFunc func(ctx context.Context, job *Job) RunResult

RunFunc is the function called when a job fires. It receives the job so it can use model/timeout overrides.

type RunLogEntry

type RunLogEntry struct {
	TS             int64  `json:"ts"`
	JobID          string `json:"jobId"`
	Action         string `json:"action"` // "finished"
	Status         string `json:"status"` // "ok", "error", "skipped"
	Error          string `json:"error,omitempty"`
	Summary        string `json:"summary,omitempty"`
	Delivered      bool   `json:"delivered,omitempty"`
	DeliveryStatus string `json:"deliveryStatus,omitempty"`
	DeliveryError  string `json:"deliveryError,omitempty"`
	SessionID      string `json:"sessionId,omitempty"`
	SessionKey     string `json:"sessionKey,omitempty"`
	RunAtMs        int64  `json:"runAtMs"`
	DurationMs     int64  `json:"durationMs"`
	NextRunAtMs    int64  `json:"nextRunAtMs,omitempty"`
	Model          string `json:"model,omitempty"`
	Provider       string `json:"provider,omitempty"`
	InputTokens    int    `json:"inputTokens,omitempty"`
	OutputTokens   int    `json:"outputTokens,omitempty"`
}

RunLogEntry is a single run history record.

type RunLogPage

type RunLogPage struct {
	Entries []RunLogEntry `json:"entries"`
	Total   int           `json:"total"` // total matching entries
	HasMore bool          `json:"hasMore"`
}

RunLogPage is a paginated result.

func ReadRunLogPage

func ReadRunLogPage(dir, jobID string, opts RunLogPageOpts) (RunLogPage, error)

ReadRunLogPage reads paginated run log entries from a job's JSONL file.

type RunLogPageOpts

type RunLogPageOpts struct {
	Limit          int    // 1-200, default 50
	Offset         int    // default 0
	Status         string // "all", "ok", "error", "skipped"
	DeliveryStatus string // "" = all
	SortDir        string // "asc" or "desc" (default "desc")
	Query          string // text search in summary/error
}

RunLogPageOpts controls paginated reads.

type RunResult

type RunResult struct {
	Text string
	Err  error
}

RunResult is returned by RunFunc after a job completes.

type Schedule

type Schedule struct {
	Kind      string `json:"kind"`                // "every"
	EveryMs   int64  `json:"everyMs,omitempty"`   // interval in milliseconds
	AnchorMs  int64  `json:"anchorMs,omitempty"`  // epoch ms reference point
	StaggerMs int64  `json:"staggerMs,omitempty"` // max stagger window (0 = auto for hourly+)
}

Schedule defines when a job runs (OpenClaw format).

Jump to

Keyboard shortcuts

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