Scheduler

The built-in scheduler runs scripts on a schedule — no cron on the server (the system task scheduler) and no other external tools are needed. The whole schedule is one file, schedule.yml, in the scripts folder, managed by the agent: you ask in chat “run every day at 9 a.m.” — the agent adds the entry itself.

How the schedule is arranged

The schedule.yml file is a list of entries. Each entry has:

  • id — the entry’s name;
  • script — the script’s path inside the folder;
  • a description — what this task is for;
  • and one of two: every — an interval (for example 15m, 24h, 7d) or cron — an exact time as six fields: seconds, minute, hour, day of month, month, day of week (in UTC);
  • extra flags: enabled (the entry is on), overlap — what to do when the previous run is still going (skip or queue), catchUp — whether to catch up on missed runs;
  • and optionally: args — the arguments passed to the script, timeoutMinutes — the max run time of this exact entry, hooks.afterRun — afterRun hooks (see below).

Intervals: no drift

A new interval entry runs immediately, then ticks on a fixed grid: every 15 minutes, every 24 hours — precisely, with no accumulated lag. If the application was down (say, the server rebooted), the next run is the grid’s first point in the future, not a “floating” time counted from the restart.

Exact times

An exact-time entry waits for its clock match (UTC): “every weekday at 7:00”. An expression with no future occurrence (February 31, say) is not lost — it is rechecked later.

All-or-nothing validation

The whole file is validated at once: one bad entry — and the entire new file is rejected, while the last working version of the schedule stays in force. It is impossible to break the schedule with a single typo; the data never loses its runs. A missing file is not an error: there is simply no schedule, and nothing runs.

Missed runs

If a run’s time came while the application was off, the run fires at startup (when catchUp is enabled) or is skipped by the queue’s rules. Runs are never lost silently — the behavior is always predictable, and no burst of back-runs ever piles up.

afterRun hooks

One run often pulls the next one behind it: extract the raw data — and the reporting database needs rebuilding from it. Before, that meant a second schedule entry and hoping it would not fire before the extract finished. Now an entry can carry afterRun hooks (in the file — hooks.afterRun): scripts that launch after the entry’s own run finishes.

Each hook says when to fire: after success (the default), after failure, or either way. The extract and the build then follow each other strictly, and if the extract fails, a checking script notices it in time.

A hook is an ordinary run: it has its own row in the history and its own output, and it can be stopped. The run shows it started after a parent, with a link to that parent run. A hook failing never rewrites the parent’s outcome — that one is already finished. Hooks do not branch: a hook never launches further hooks of its own, the chain ends on it. One entry can carry up to eight hooks.

Managing from the interface

The Scheduler section lists every entry: what runs, when and at what interval, and which afterRun hooks the entry carries. From here you can pause the whole schedule at once, put one entry on hold, run a script right now with the “Run now” button, and browse the schedule’s run history. The file itself is not edited in the interface: ask for schedule changes in chat — the agent updates schedule.yml, and the changes are picked up on the fly, without restarting the application.

See also: Runs, Chat with the Agent.

← Back to the documentation index