How Each Mode Works¶
single¶
Each tick, the Processor calls pgrelay.should_dispatch_single() (which simply returns NOT pg_is_in_recovery() — PostgreSQL's own function for "am I currently a standby replaying changes?"). On a writable primary, it dispatches normally; on a read-only standby, it idles and logs standby_waiting. On promotion, it logs primary_active and starts dispatching. Failover latency here is entirely down to how fast your HA layer promotes the standby.
multi-node¶
- At startup, and on every reload, before its first tick, the Processor runs
pgrelay._startup_queue_check()— a catch-all that re-homes any pending row whose owner is not a configured Spock node (in other words, a decommissioned or unrecognised owner) onto this node, so nothing is ever left permanently stuck. - On every tick, before dispatching, it runs
pgrelay.multi_master_watch()— the conservative adoption watcher (see Deciding If a Node Is Dead). It then dispatches its own owned rows (theowner_nodefilter, applied insidequeue_pending_ids()/_queue_claim(), restricts each node to only the rows whereowner_nodematches its own node).
leader¶
Each tick, the Processor calls pgrelay.is_lowest_live_master() and publishes the result to its own connections as the pg_relay.is_leader session setting (logging leader_acquired / leader_yielded whenever this changes). Every node then goes on to dispatch — what leadership actually changes is only the scope the SQL dispatch rule grants it:
- the leader is offered its own node-restricted rows, plus every unrestricted row, regardless of which node created it;
- a non-leader is offered only its own node-restricted rows (see Node-Restricted Channels). With no restricted channels registered, its candidate query simply returns nothing — one cheap, indexed query per tick, and no wasted work.
A row offered to a node under stale leadership (for example, if leadership changed hands a moment ago) fails re-validation at the moment it is claimed — _queue_claim() applies the same rule — and is simply skipped.
Continue to Deciding If a Node Is Dead for how adoption and leader election actually decide a peer has failed.