Evaluation Engine¶
pghf.evaluate_run(p_run_id uuid)¶
The evaluation dispatch engine. Judges one already-collected run's raw results against configured thresholds, one row per check, producing a raw_severity from the 8-value ladder pghf._severity_rank() defines: a SKIPPED raw result becomes 'skipped'; an ERROR one becomes 'error_in_performing_check'; a threshold with a custom evaluator attached is dispatched to it (an exception there becomes 'invalid'); a threshold without one goes through the built-in, direction-aware comparator (an exception there also becomes 'invalid'; its own ordinary 'not_evaluable' returns stay 'not_evaluable'); no threshold at all is 'not_evaluable'. Applies debounce (strict-consecutive or windowed-tolerance, optionally bounded by a wall-clock window) and then hysteresis (symmetric-recovery, if configured) to produce the confirmed severity, then fires any qualifying events. Commits after each check. Deliberately not SECURITY DEFINER — the same reasoning as the collection engine: a custom evaluator is dynamic dispatch of a function read out of a table. Must be invoked as a standalone CALL statement.
| Parameter | Type | Mandatory | Default | Description |
|---|---|---|---|---|
p_run_id |
uuid |
Yes | — | An already-collected run. Must exist. |
Returns: nothing. This is a procedure. Writes one evaluation record per raw result. May only be called once per run, and raises on a second attempt. Also raises on a pg_relay-dispatched run that hasn't finished collecting yet (its workers may still be writing results, and evaluating early would permanently lock the late-landing checks out of a verdict) — wait for pghf.get_run_status() to report collection complete, or use pghf.run_and_evaluate() below, which waits for you. A sequential run is deliberately not gated this way: for those, unfinished means crashed, and evaluating what was collected before the crash remains legitimate.
pghf.get_debounce_status(p_check_id text)¶
Read-only introspection into a check's current debounce/hysteresis progress — one evaluation stream per check, across every suite that runs it — without hand-querying pghf.evaluations; see Debounce for a full worked example. Returns one row: current raw/confirmed severity, which debounce mode applies ('none'/'strict_consecutive'/'windowed_tolerance'), how many of the required breaches (or clears) have accumulated, whether it's actually confirmed, and — when a time window is configured — the check's observed average run gap and whether that window looks achievable. Achievability accounts for breach debounce and hysteresis independently — true only if every side that's actually enabled fits the window (a window backed only by min_consecutive_clears, breach debounce left off, is judged purely on the clear side). SECURITY DEFINER.
| Parameter | Type | Mandatory | Default | Description |
|---|---|---|---|---|
p_check_id |
text |
Yes | — | Check to check debounce status for. Must exist. |
Returns: one row (see above). Raises if the check doesn't exist; returns an all-empty row (not an error) if the check has simply never been evaluated yet.
pghf.run_and_evaluate(p_run_key text DEFAULT NULL, p_check_run_id uuid DEFAULT NULL, INOUT p_run_id uuid DEFAULT NULL, p_target_version int DEFAULT NULL, p_amcheck_tables text[] DEFAULT NULL, p_pg_visibility_tables text[] DEFAULT NULL, p_relay_wait interval DEFAULT '5 minutes', p_critical_only boolean DEFAULT false)¶
Convenience wrapper: calls the collection engine, then the evaluation engine, in a single CALL. Same parameters as pghf.execute_check_run(), plus one of its own. This works only because it's a procedure calling two other procedures that each commit internally — wrapping either one in an ordinary function instead would fail. Deliberately not SECURITY DEFINER, for the same reason as its two callees. Must be invoked as a standalone CALL statement.
For a pg_relay-dispatched run, collection finishes asynchronously in relay workers, so between the two stages this procedure polls for the run's finish time — up to p_relay_wait — before evaluating, committing between polls so it holds nothing open while it waits. On timeout it raises, leaving the run itself intact and still completing; evaluate it manually with pghf.evaluate_run() once pghf.get_run_status() reports collection complete. For a sequential run, p_relay_wait is never consulted.
| Parameter | Type | Mandatory | Default | Description |
|---|---|---|---|---|
p_run_key |
text |
One of p_run_key/p_check_run_id required |
empty | Suite to run, by name. |
p_check_run_id |
uuid |
One of p_run_key/p_check_run_id required |
empty | Suite to run, by internal identifier. |
p_run_id |
uuid (input/output) |
No | empty = a new one is generated | Same as pghf.execute_check_run(). |
p_target_version |
int |
No | empty | Same as pghf.execute_check_run(). |
p_amcheck_tables |
text[] |
No | empty | Same as pghf.execute_check_run(). |
p_pg_visibility_tables |
text[] |
No | empty | Same as pghf.execute_check_run(). |
p_relay_wait |
interval |
No | '5 minutes' |
pg_relay-dispatched runs only: how long to wait for the relay workers to finish collecting before giving up (raising, with the run left intact). |
p_critical_only |
boolean |
No | false |
Same as pghf.execute_check_run()'s own — passed straight through. Note the parameter order here: appended after p_relay_wait, not alongside its position in execute_check_run(), so p_relay_wait keeps a stable positional index for existing callers. |
Returns: the run ID, via the input/output parameter. Reading results back out afterward is still a separate call — see Reporting.
pghf.run_and_evaluate_check(p_check_id text, INOUT p_run_id uuid DEFAULT NULL, p_severity text DEFAULT NULL, p_record_pk jsonb DEFAULT NULL, p_detail jsonb DEFAULT NULL, p_target_version int DEFAULT NULL, p_amcheck_tables text[] DEFAULT NULL, p_pg_visibility_tables text[] DEFAULT NULL)¶
The on-event counterpart to pghf.run_and_evaluate() above: calls pghf.execute_check() (see Collection Engine), then pghf.evaluate_run(), in a single CALL, for one check standalone rather than a whole suite. pghf.execute_check() itself stays collect-only, matching pghf.execute_check_run()'s own contract — this is the explicit opt-in for "and judge it too."
For manual, top-level invocation only — same rule as pghf.execute_check(), which it wraps: never callable from inside a trigger or function. A trigger can only ever reach pghf.execute_check_event(), which can never itself evaluate (see On-Event Checks) — use pghf.evaluate_pending_event_alerts() below for whatever a trigger has collected.
| Parameter | Type | Mandatory | Default | Description |
|---|---|---|---|---|
p_check_id |
text |
Yes | — | The check to run and evaluate. |
p_run_id |
uuid (input/output) |
No | empty = a new one is generated | Same convention as pghf.execute_check(). |
p_severity / p_record_pk / p_detail |
— | No | empty | Same as pghf.execute_check() — the calling event's own verdict and evidence, see On-Event Checks. |
p_target_version / p_amcheck_tables / p_pg_visibility_tables |
— | No | empty | Same as pghf.execute_check(). |
Returns: the run ID, via the input/output parameter.
pghf.evaluate_passthrough_severity(p_run_id uuid)¶
The shipped, generic evaluator for on-event checks. Where every other evaluator_routine in this codebase is written for and hardcodes one specific check_id, this one has no judgment to apply, so it has nothing to hardcode: it reads observed->>'severity' and returns it verbatim as the evaluation's severity, carrying the rest of observed (record_pk/detail) through into the evaluation's own detail field. Any number of on-event checks' thresholds may point at this exact same function — safe because, unlike pghf.checks.routine, pghf.thresholds.evaluator_routine has no uniqueness constraint.
Register it the same way as any custom evaluator:
SELECT pghf.set_threshold('X01-003', p_evaluator_routine => 'pghf.evaluate_passthrough_severity(uuid)'::regprocedure);
| Parameter | Type | Mandatory | Default | Description |
|---|---|---|---|---|
p_run_id |
uuid |
Yes | — | Same signature as every evaluator_routine — see Writing a Custom Evaluator. |
Returns: pghf.evaluation_result. 'not_evaluable' if observed has no 'severity' key at all (nothing to judge, not an error — e.g. a check registered with this evaluator whose routine didn't actually populate it). Raises — becoming 'invalid' via pghf.evaluate_run()'s own exception handling around evaluator dispatch — if the value present is outside ok/info/warning/critical; defense-in-depth only, since pghf.execute_check_event() already validates p_severity at call time.
pghf.evaluate_pending_event_alerts(p_limit int DEFAULT NULL)¶
Judges whatever a trigger has already collected but nothing has evaluated yet. This is the piece that makes on-event checks actually alert, not merely record: pghf.execute_check_event() is deliberately no-commit so it's safe to call from a trigger, but pghf.evaluate_run() commits internally — the same hard rule that keeps it out of any atomic context — so a trigger can never evaluate what it just collected. This procedure is where that evaluation happens instead: it finds every finished, not-yet-evaluated run grouped under the reserved event_alerts suite (see Suites) and evaluates each, oldest first.
This is a real operational step, not an optional nicety. Schedule it on a short interval (a cron/pg_cron entry — see Scheduling Health Checks) if you want an on-event check's thresholds, debounce, and events to actually fire. Skipping it leaves collected data sitting in pghf.raw_results with no severity ever judged.
| Parameter | Type | Mandatory | Default | Description |
|---|---|---|---|---|
p_limit |
int |
No | empty = unbounded | Caps how many pending runs one call evaluates — a safety valve against one sweep running long behind a very bursty event source, not a true batched retry loop (compare pghf.purge_results_before_batched()). Call again to pick up whatever it left behind. |
Returns: nothing. This is a procedure. Raises a notice reporting how many runs it evaluated (silent if none were pending). Deliberately not SECURITY DEFINER, same reasoning as pghf.evaluate_run() itself. Must be invoked as a standalone CALL statement.
Continue to Built-in Custom Evaluators.