Notifications¶
A notification is a subscription scoped to one check, one category, or globally (every check), that fires when a check's confirmed severity meets a configured severity set. Two firing policies, chosen per subscription: on_change fires on a transition into the set (a 'breach'), and — with fire_on_clear — back out of it (a 'clear'); on_state fires on every evaluation whose severity is in the set (a 'state' firing), throttled only by an optional cooldown. Every firing lands in the durable outbox pghf.notification_log first, then is delivered per its delivery_kind. See How Firing Actually Works for the full semantics.
pghf.create_notification(p_notification_name text, p_delivery_kind text, p_check_id text DEFAULT NULL, p_namespace_code text DEFAULT NULL, p_category_code text DEFAULT NULL, p_trigger_mode text DEFAULT 'on_change', p_severities text[] DEFAULT NULL, p_min_severity text DEFAULT NULL, p_fire_on_clear boolean DEFAULT false, p_cooldown_minutes integer DEFAULT 0, p_run_sequence integer DEFAULT 100, p_channel_name text DEFAULT NULL, p_routine regprocedure DEFAULT NULL, p_function_args jsonb DEFAULT NULL, p_is_active boolean DEFAULT true)¶
The only way to add a notification. Scope with exactly one of a check or a category, or neither for a global subscription. Works on any existing check or category, built-in or your own.
| Parameter | Type | Mandatory | Default | Description |
|---|---|---|---|---|
p_notification_name |
text |
Yes | — | A label; every journalled firing carries it. |
p_delivery_kind |
text |
Yes | — | 'outbox' (pending only, a pull consumer drains it), 'notify' (pending + a standard PostgreSQL NOTIFY doorbell — plain core Postgres, no pg_relay), 'pg_relay_notify' (pending + a pg_relay pgrelay.notify() enqueue for worker delivery — requires the pg_relay extension, and registration is rejected if it isn't installed), or 'function' (pending + an inline routine). notify and pg_relay_notify both need p_channel_name. |
p_check_id |
text |
No | empty | Scope to one check. Mutually exclusive with the category arguments. |
p_namespace_code / p_category_code |
text |
No | empty | Together, scope to one category. Must be given together. |
p_trigger_mode |
text |
No | 'on_change' |
'on_change' (fire on a transition across the set) or 'on_state' (fire on every in-set evaluation — per-occurrence). |
p_severities |
text[] |
One of p_severities/p_min_severity required |
empty | The exact set of confirmed severities that qualify (any of the 8 ladder values). |
p_min_severity |
text |
One of p_severities/p_min_severity required |
empty | Convenience: expands to the rank-≥ floor set (e.g. 'warning' → warning/invalid/critical/error_in_performing_check), matching list_alert_status()'s floor. |
p_fire_on_clear |
boolean |
No | false |
on_change only: also fire a 'clear' when the check leaves the set. Rejected with on_state. |
p_cooldown_minutes |
integer |
No | 0 |
Engine-guaranteed throttle from the last firing (anti-flap: an intervening severity never resets it). 0 = fire on every qualifying evaluation. on_state only — a non-zero cooldown is rejected on on_change (whose anti-flap is the check's own debounce/hysteresis). |
p_run_sequence |
integer |
No | 100 |
Firing order when several notifications match one evaluation. |
p_channel_name |
text |
No | empty | Required for 'notify': the doorbell channel. |
p_routine |
regprocedure |
No | empty | Required for 'function': a (bigint, bigint, jsonb) RETURNS void routine — (p_notification_log_id, p_evaluation_id, p_args). |
p_function_args |
jsonb |
No | empty | Passed to the routine verbatim as its third argument — your own free-form config. |
p_is_active |
boolean |
No | true |
false registers it dormant until turned on. |
Returns: bigint — the new notification's identifier. Only a role explicitly granted permission can call this (the 'function' routine later runs, invoker-rights, inside every pghf.evaluate_run()).
pghf.update_notification(p_notification_id bigint, p_notification_name text, p_delivery_kind text, p_is_active boolean, p_trigger_mode text DEFAULT 'on_change', p_severities text[] DEFAULT NULL, p_min_severity text DEFAULT NULL, p_fire_on_clear boolean DEFAULT false, p_cooldown_minutes integer DEFAULT 0, p_run_sequence integer DEFAULT 100, p_channel_name text DEFAULT NULL, p_routine regprocedure DEFAULT NULL, p_function_args jsonb DEFAULT NULL)¶
The only way to modify a notification. Scope is immutable — delete and re-create to re-scope. Full replace of every other field, including p_is_active. last_fired_at is engine-owned and untouched — an update never resets a cooldown.
Returns: bigint — the identifier. Only a role explicitly granted permission can call this.
pghf.delete_notification(p_notification_id bigint)¶
Permanently deletes a notification (no soft-retire — use update_notification(..., p_is_active => false) to inactivate without losing configuration). Already-journalled firings stay in pghf.notification_log.
Returns: nothing. Only a role explicitly granted permission can call this.
pghf.get_notification(p_notification_id bigint) / pghf.list_notifications(p_check_id text DEFAULT NULL, p_only_active boolean DEFAULT NULL)¶
get_notification() returns one record by id (raises if not found). list_notifications() lists them in run_sequence order; p_check_id filters to the ones applicable to that check — its own, its category's, and global rows (exactly what the dispatcher considers), and p_only_active filters by active state.
Returns: the record / zero or more records. Callable by anyone.
The outbox — pghf.notification_log¶
One durable row per firing, written only by the dispatcher: the notification, trigger mode, transition ('breach'/'clear'/'state'), old/new status, triggered severity, the matched set, delivery details, and a self-contained payload — which includes record_pk and source_table, so an on-event notification pinpoints the offending row with no joins, and rows keep their meaning after retention purges. Delivery: 'outbox' waits 'pending' for a pull consumer; 'notify' also fires a standard PostgreSQL pg_notify of the row's id as a doorbell; 'pg_relay_notify' instead enqueues the row's id via pg_relay's pgrelay.notify() for worker delivery (a runtime channel/config failure is recorded on the row as 'failed' with a warning, not swallowed); 'function' runs its routine inline and the engine marks the row 'delivered'/'failed'. Not openly readable; the functions below are the supported access. Prune with pghf.purge_notification_log_before().
pghf.list_pending_notifications(p_limit int DEFAULT 100)¶
The delivery consumer's work queue: outbox rows still 'pending', oldest first.
Returns: zero or more outbox records. Callable without any direct table grant.
pghf.mark_notification_delivered(p_notification_log_id bigint, p_success boolean DEFAULT true, p_note text DEFAULT NULL, p_detail jsonb DEFAULT NULL)¶
The delivery acknowledgement — marks one outbox row 'delivered' (default) or 'failed' (with p_note/p_detail). Used both by an async outbox/notify consumer and by an inline 'function' routine reporting its own outcome. Re-markable.
Returns: nothing. Invoker-rights (writes through the open INSERT/UPDATE grant on the outbox). Raises if the row doesn't exist.
pghf.list_notification_log(p_check_id text DEFAULT NULL, p_delivery_status text DEFAULT NULL, p_since timestamptz DEFAULT NULL, p_limit int DEFAULT 100)¶
The firing audit trail, newest first — "did we notify on this, and was it delivered?" in one query. Filters: one check, one delivery status ('pending'/'delivered'/'failed'), a start time, a row cap.
Returns: zero or more outbox records. Callable without any direct table grant.
pghf.notification_context(p_evaluation_id bigint)¶
The "wire in your own delivery" helper: everything a notification routine (or an outbox consumer) needs from an evaluation, in one call — check_id, check_name, category_id, execution_mode, source_table, severity, message, record_pk, event_detail, run_id, occurred_at. For an on-event check, record_pk/source_table pinpoint the offending row; for a polled check record_pk is null.
Returns: one row (see above). Raises evaluation % not found for a bad id. Callable without any direct table grant.
pghf.register_run_hook(p_hook_name text, p_routine regprocedure, p_run_sequence integer DEFAULT 100, p_is_active boolean DEFAULT true)¶
Registers — or, for an existing name, replaces — a run hook: a routine the evaluation engine calls exactly once per evaluated run, with the run id, inside the final evaluation's transaction (every evaluation of the run is visible to it; its work commits or rolls back with the last evaluation). Hooks fire in run_sequence order; a raising hook is a warning, never a failed evaluation, and the next hook still runs. Runs with the evaluating role's own rights — the run-level counterpart of a notification.
| Parameter | Type | Mandatory | Default | Description |
|---|---|---|---|---|
p_hook_name |
text |
Yes | — | The hook's name; upserted on. |
p_routine |
regprocedure |
Yes | — | Validated at registration: exactly (uuid) RETURNS void. |
p_run_sequence |
integer |
No | 100 |
Firing order among hooks. |
p_is_active |
boolean |
No | true |
false registers it dormant (or silences an existing one). |
Returns: bigint — the hook's identifier. Only a role explicitly granted permission can call this (the same trust tier as registering a notification routine).
pghf.unregister_run_hook(p_hook_name text)¶
Removes a run hook by name. Raises if it doesn't exist. Only a role explicitly granted permission can call this.
pghf.list_run_hooks(p_only_active boolean DEFAULT NULL)¶
Lists run hooks in firing order. p_only_active: empty = all, true/false filters. Callable by anyone.
Continue to Evaluation Engine.