Skip to main content
A missed occurrence is never silently dropped: set misfire_grace_seconds and a stale slot is recorded as missed in history instead of firing a no-longer-useful run.

Quick Start

1

Set a grace window

Set misfire_grace_seconds so a stale slot after downtime is recorded rather than fired.
2

Same job in YAML

3

Leave it unset for the old behaviour

Leaving misfire_grace_seconds unset (or None) preserves the pre-existing behaviour — a missed occurrence still coalesces into one fire on recovery.

How It Works

On recovery the store looks at each due job, computes the epoch of the occurrence it is firing for, and either fires (within grace / first run) or records missed (past grace).

What The User Sees

Silence, not a stale ping — a broken window shows up as a missed row in run history so an operator can spot the gap on the same page they read successes and failures.

Kinds — how the “occurrence” is derived

scheduled_instant() derives the recovered slot per Schedule.kind, so you can reason about which fire is being suppressed.

Configuration Options

Full field reference for the job dataclass
All run status values and history fields
The one knob this feature introduces. The new RunRecord.status value.

Common Patterns

A daily brief tolerates a short delay but not a multi-hour one.
An interval poll with a wide grace fires after a brief restart but skips a slot after a multi-hour outage.
A first run always fires — the policy only applies to recovered recurrences.

Best Practices

The grace is “how late can this slot still be useful?” — a daily 07:00 brief probably tolerates 10 minutes but not 6 hours; an hourly poll of live data might tolerate 30 seconds.
None (the default) is the right choice when a coalesced late fire is still valuable — the previous behaviour is preserved byte-for-byte.
A cluster of missed rows across jobs is a downtime marker — combine it with Scheduler Incidents so a broken schedule and a broken job are both surfaced.
_coerce_optional_float will accept "3600" in a hand-edited config, but the intended form is unquoted (misfire_grace_seconds: 3600). Non-numeric junk fails safe to “no misfire policy”.

Cross-run notepad the scheduler already persists
Alert once when a scheduled job breaks
Silence-when-unchanged sibling — declarable monitor spec
The async runner that observes the policy