Skip to content

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.