job-failure-handling — what a failed scheduled job triggers¶
Detection, unchanged re-run, notification, ticketing and logging. Never invokes Claude/Codex/any agent, never changes code, never pushes (owner constraint 2026-10-06). Procedure: SOP-043.
Parts¶
| Piece | Where |
|---|---|
| logic (classify, policy, fold, sweep, retry, report) | ~/assistant/job_failure.py (tests tests/test_job_failure.py); fix task = jobs_api.ensure_fix_task |
| entry points | ~/.local/bin/job-failure hook|hook-unit|sweep|retry|report; ~/.local/bin/job-incidents (open incidents; --all, --json, fix <job> <commit>) |
| trigger 1 | cron-run calls job-failure hook on non-zero exit (exit 0 = handled, legacy alert skipped; else legacy alert) |
| trigger 2 | ~/.config/systemd/user/service.d/10-job-failure.conf OnFailure=job-failure@%n.service for every user service; hook ignores non-catalogue units |
| trigger 3 | crontab */10 * * * * cron-run job-failure-sweep (safety net, escalates deferred, closes green incidents) |
| weekly | crontab Mon 07:20 cron-run job-failure-report → app notify + ntfy |
| log | incidents.jsonl (append-only events; incidents are folded, no other state) |
Decisions¶
- Transient = DNS/network, timeout, HTTP 429/5xx, rate limit, "empty or not JSON", lock/database busy. Hard errors win over transient words. Unknown = permanent.
- Re-run after 240 s via
systemd-run --user --on-active, max 2 per job per local day, through the job's own crontab command (orsystemctl --user start), withJOB_FAILURE_RETRY=1so cron-run stays quiet and the re-run reports its own outcome. - Frequent jobs (cron every ≤15 min) are deferred 30 min instead of re-run.
- Deny-list =
DENYinjob_failure.py(see SOP-043); default for an unlisted job is re-run. - The
fixercron job (separate, pre-existing) still reads heartbeats and may retry/diagnose on its own; this process does not use it.
If you change this¶
- Hits:
cron-run(hook block),jobs.jsoncatalogue (hook only knows catalogued jobs; runjobs-indexafter adding one), cron-watch limits forjob-failure-sweep/-report. - Rollback: delete the hook block in
cron-run(legacy alert returns), remove the crontab lines andservice.d/10-job-failure.conf.
Fixer PRs on Home (2026-10-17)¶
fixer-prs-refresh (cron */15, ops-scripts) lists open PRs labelled "job-fixer week-1: owner approves" in ops-scripts, assistant and story-publisher into ~/.local/state/cockpit/prs.json. Home's "Needs you" card (admin only) shows them as "Fix PR waiting:
Frequent jobs defer on any failure (2026-10-25)¶
A job that reruns within 15 min (is_frequent) now defers on any class, not only transient: the next run is the retry and the sweep escalates after 30 min if it stays red. Deny-listed frequent jobs keep the old rule (permanent → escalate). Cause: booking-warm paged on one silent curl exit 23. assistant cf870a8.
Weekly report (2026-10-25) appends storage_line(): reads ~/.local/state/storage-forecast/summary.json + reclaim.jsonl (assistant 4a9cbba).