Skip to main content
Turn a stream of scheduled-run failures into a single de-duped operator alert — one ping when a nightly job breaks, one when it recovers, nothing in between.

Quick Start

1

Just enable it

Incidents ride on top of the scheduler notepad, so the wrapper attaches the tracker automatically when you run from the scheduler — RunPolicy.alert_after_failures is the one knob you tune from the outside.
2

Drive ticks yourself

Use the pure tracker when you drive ticks (custom runner, tests, out-of-process cron).
3

Tolerate transient blips


How It Works

The scheduler loads per-job state, runs the tick, folds the resulting RunRecord through the tracker, and delivers only when an alert is due. Curious how this is wired end-to-end? See Scheduled Run Policy → Failure Alerting — Once Per Incident.
A job parked by the Provider-Quota Hold also folds through this incident tracker for consistent failure/recovery accounting — but its “held until N” notice is emitted even below alert_after_failures, because a silent park would otherwise leave the operator unaware the job was benched.

What Counts As “The Same” Failure

Failures collapse to one incident when their error_signature matches, and normalise_error strips only the volatile parts of a message before hashing. The normaliser then keeps a prefix of the first 200 chars and sha256s it.

Tolerating Transient Blips

Set after_failures=N to alert only when the same failure repeats N ticks in a row — a single flaky tick that recovers never pages you.
A blip that recovers before the threshold never alerted, so it sends no recovery note either.
Pick a threshold with this decision tree:

Wiring the Alert

The returned Incident carries the raw error for the alert body; hand it to the job’s existing delivery target — there is no new delivery API.

Recovery Notes

On the next success after an alerted incident, the wrapper delivers a single recovery note through the same channel:
The recovery note is only sent when deliver_on_failure is on — it is the mirror of the failure alert.
The recovery note is committed to durable state only after it is delivered. If the recovery send fails, the incident stays open and the next successful run retries the note exactly once.

Configuration Options

IncidentTracker takes one option. Each incident is a small dataclass persisted per job.
Full SDK reference
Fields, serialization

Common Patterns

Persist tracker state through the store you already use for the notepad — the incident dict round-trips as-is.
Reuse the job’s delivery target for the alert — no second channel.
Raise the threshold for a chatty external API so occasional 429s do not page you.

Best Practices

Send incident alerts through the same DeliveryTarget the job already uses — don’t set up a second channel.
Use 1 or 2 for hourly/daily jobs. A high threshold delays detection because it needs that many consecutive ticks first.
Don’t call IncidentTracker from inside an agent tool — it’s a runner-level concern. The scheduler wraps it for you.
Persist incident state through the same store you use for the job-state notepad, not a new one.

RunPolicy — the alert_after_failures knob
Where the alert is delivered
The state store incident data rides on
Misfire Policy — record a slot missed while the process was down