Skip to main content
A job that runs every thirty seconds for a week will fail sometimes. A rate limit, a dropped connection, a provider hiccup. The question is not whether it fails but what happens next.

The model

A task that raises is logged and retried on the next tick. It does not take the schedule down. That is how cron behaves, and it is the only sensible default for something meant to run unattended.
Earlier versions did the opposite: one exception set is_running = False and killed the scheduler thread, while run() returned a job object as though nothing had happened. A single transient failure permanently stopped the job, and the caller was handed a plausible return value and a dead schedule.

Error budgets

Retrying forever is right for transient failures and wrong for a misconfigured job hammering a dead endpoint. max_consecutive_errors draws the line.
  • None (default): never give up. Every failure is logged, every tick retried.
  • An integer: after that many failures in a row, the job stops and run() raises CronJobExecutionError naming the count and the last error.
The counter resets on any success, so a job that fails occasionally never trips the budget. Only a job failing consistently does.
That distinction is the important part: a clean stop() returns, a job that gave up raises. You can tell them apart.

Monitoring while it runs

get_execution_stats() is safe to poll from another thread.

What to watch

error_count on its own is a poor signal: a job running every two seconds for a day will accumulate failures and be perfectly healthy. consecutive_errors is the one that distinguishes noise from breakage.

A complete example

Runs without API keys, since FlakyAgent stands in for an unreliable upstream.
A representative run: 19 successful executions and 21 failures over sixty seconds, never stopping, because the failures never stacked ten deep in a row.

Budgets across a fleet

With run_many, budgets are per agent. One agent giving up does not stop its siblings:
If the flaky agent exhausts its five, it stops, the stable one keeps running, and run_many raises once blocking ends, naming which job gave up.

Next steps

Multiple Agents

Fleets on mixed cadences

CronJob Quickstart

Start with a single agent

CronJob Reference

Full parameter and method documentation

Runnable Examples

The example files in the repository