Skip to main content

Recurring Jobs

Cron-based scheduled jobs with name, schedule, type, next/last execution times, and the outcome of the last run.

The list is built to be scanned: the Schedule column reads the cron expression back in plain English ("Every 15 minutes"), and Next / Last Execution answer "when, roughly?" ("in 10 minutes", "5 minutes ago"). Both tick live; Next Execution is a countdown, so a definition whose scheduler has stopped reads overdue by 5 minutes rather than quietly flipping to the past tense. In both cases the precise value — the raw expression, the exact timestamp — is on hover, and the timestamps render to the minute, since a cron occurrence is only ever minute-aligned.

The Schedule header doubles as a switch: it names whichever half is in the cell (Schedule or Cron) and clicking it swaps them, persisted per browser. Relative times follow the viewer's locale.

How Recurring Jobs Work​

AddOrUpdateRecurringJob only registers (or updates) the recurring job definition — it does not create any job instances. The RecurringJobScheduler background task monitors all definitions and creates a new job each time the cron expression fires.

Execution History​

Each recurring job tracks its executions via RecurringJobLog entries. The history table shows the outcome of each scheduled run:

  • Normal executions link to the job and show its current state
  • If the underlying job has been cleaned up, the entry still shows its outcome, followed by a muted "(cleaned up)" — the result is preserved even though there is no job detail page left to open
  • If the recurring job was disabled at the time, the entry displays an orange "Skipped" badge

The list page condenses this into a Last Result column showing the state of the most recent real run (skipped firings are not runs, so a disabled job keeps showing the outcome of its last actual execution). The Last Execution timestamp links to that run's job too, so either half of the row gets you there.

Four states are distinguishable:

DisplayMeaning
—the definition has never actually fired
badge, linkedthe job row is still there — click through to it
badge + (cleaned up)the job row was swept, but its outcome was preserved
Cleaned upswept by a deployment older than 6.1, before outcomes were preserved

That third state matters most for low-frequency definitions: with the default 1-day job retention, a monthly job's rows are long gone before the next firing, so before 6.1 its entire history read Cleaned up. See Recurring Jobs for how the outcome is preserved.

Dashboard Actions​

  • Enable / Disable — toggle whether the scheduler creates real jobs or skips. Disabled jobs still fire on schedule but record "Skipped" entries in the history instead. The recurring job list shows an Enabled or Disabled badge per row. A disabled definition shows — for Next Execution (it will not execute while disabled) and its Last Execution stays pinned to the last occurrence that actually ran — Never if it never ran.
  • Trigger — immediately creates and enqueues a new job instance, regardless of the cron schedule or disabled state
  • Delete — removes the recurring job definition (existing job instances are not affected)

For full documentation on configuring and using recurring jobs, see Recurring Jobs.

Click a recurring job name to see its detail page with execution history: