# Ops Cockpit — Cron Health Monitor (`do_cron_health`)

Records **every** `ir.cron` run and surfaces health, so silent cron failures
stop being invisible. Part of the Ops Cockpit suite; depends on
[`do_ops_alert_base`](../do_ops_alert_base).

## What it does

| Piece | Behaviour |
|-------|-----------|
| `do.cron.health.log` | One row per run: start/end, duration, outcome, traceback, scheduled-vs-manual. Read-only to users. |
| `ir.cron` wrapper | Overrides `_run_job` (boundary + duration + outcome) and `_callback` (exact traceback); writes log rows on a **separate, independently-committed cursor** so failed runs survive the job's rollback / a worker crash. |
| Computed health | `do_health_status` (good/warning/critical), `do_last_*`, `do_avg_duration`, `do_is_overrunning` — computed from the log table (2 batched SQL queries), never stored on the locked cron row. |
| Watchdog cron | Marks runs still `running` past a threshold as `stale`; fires throttled alerts on failure / overrun / recovery. |
| Dashboard | Cron Health list (colour-coded), run logs (list/graph/pivot/form), a health smart-button + health group on the cron form. |
| Retention | `@api.autovacuum` purges old log rows. |

## Why a separate cursor (the core trick)

Core locks the `ir.cron` row `FOR NO KEY UPDATE SKIP LOCKED` for the whole run,
and splits its own bookkeeping cursor (survives) from the job cursor (rolls back)
— see `odoo/addons/base/models/ir_cron.py`. We mirror this: the wrapper writes
**only** to `do.cron.health.log` (FK inserts are allowed under that lock mode) and
commits its own cursor, so the runs you most want to see are never lost. We never
`UPDATE` the locked cron row from our side cursor (that would deadlock).

## Override points (v19, verified from source)

* `_run_job(cls, job)` — single run boundary; returns `CompletionStatus`.
* `_callback(self, …)` — where the exception is raised; captured into a
  `threading.local` (auto-isolated across concurrent cron threads), re-raised.
* `method_direct_trigger` — tags manual runs.

## Settings (Settings → Ops Cockpit → Cron Health)

Monitor on/off, stale threshold, overrun multiplier, critical-after-N-failures,
log retention days.

## Tests

`./tests/test_cron_health.py` — outcome mapping, computed health roll-up,
watchdog stale-marking, throttled alert firing, retention GC.

License `LGPL-3`. Admin-only (`base.group_system`). Community deps only.
