Skip to content

Channels and Concurrency

Notifications travel through a pg_relay channel registered with the notify action type:

SELECT pgrelay_notifier.create_channel('notifications', p_max_retries => 3);
  • p_max_retries (default 3): transient failures (connection refused, timeouts, SMTP 4xx, Graph 429/5xx) are retried with backoff (3s / 5s / 10s) up to this many times, then fail terminally. Permanent failures (SMTP 5xx, bad recipients, rejected secrets) never burn retries.
  • p_concurrency_mode (default concurrent): 'channel' serializes the channel — at most one in-flight send, in strict queue order. Use it for rate-limited mailboxes or when ordering matters.
  • Every profile has a default channel (p_channel at profile creation); a send can override it.
  • All pg_relay channel machinery applies: pgrelay.disable('notifications') pauses new deliveries, pgrelay.update(...) changes retry settings, and so on.

A caveat under multi-master

'channel' serialization is cluster-wide only under --mode=single (one primary) or --mode=leader (one dispatcher cluster-wide). Under --mode=multi-node, each PostgreSQL node dispatches its own queue rows independently, so concurrency_mode = 'channel' only serializes per node — two nodes can each have an in-flight send to the same mailbox at the same time.

If a notify channel exists specifically to rate-limit or serialize access to one external mailbox or relay, run that deployment with --mode=leader (or single), not multi-node. This is a property of pg_relay's dispatch topology, not something pg_relay_notifier can enforce on its own — see Multi-Master Deployments for the full picture.