Add require_wal_receiver connection parameter to libpq

From: Jim Jones <jim(dot)jones(at)uni-muenster(dot)de>
To: PostgreSQL Hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: Add require_wal_receiver connection parameter to libpq
Date: 2026-09-05 22:56:25
Message-ID: 3289eb5b-eb37-4ba7-9cc5-10a3afbecaec@uni-muenster.de
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi,

When a connection string lists several hosts,
target_session_attrs=standby (or prefer-standby) picks the first host
that reports pg_is_in_recovery(). That confirms the server is a standby,
but says nothing about whether it still has a live WAL receiver attached
to its upstream. A standby whose primary connection was lost still
reports itself as a standby and is pretty much indistinguishable from a
healthy one, so libpq happily routes read-only traffic to a server that
potentially stopped receiving WAL for quite some time.

I'd like to propose a parameter that makes libpq look at
pg_stat_wal_receiver on the candidate standby and move on to the next
host when no WAL receiver is running there:

psql "host=h1,h2,h3 port=5111,5222,5333 dbname=db \
target_session_attrs=standby require_wal_receiver=1"

It applies on top of target_session_attrs rather than replacing it, and
is skipped where it is meaningless: on a primary, when
target_session_attrs requires a primary/read-write session, on
replication connections, and on the prefer-standby fallback pass, so
prefer-standby still degrades to "any server" instead of failing outright.

The current PoC is quite simplistic. The CONNECTION_CHECK_STANDBY state
already runs "SELECT pg_catalog.pg_is_in_recovery()" for
standby/prefer-standby, so the check rides along on that query as a
second column -- an EXISTS over pg_stat_wal_receiver. The obvious
alternative -- comparing pg_last_wal_receive_lsn() with
pg_last_wal_replay_lsn() -- does not cover the same case. A standby that
lost its upstream received everything it will ever receive and replayed
all of it, so its lag is exactly zero and it passes any threshold.

Two things I'd like input on before going forward:

1) The EXISTS test is deliberately weak. pg_stat_wal_receiver might
simply report a connection attempt, so a WAL receiver stuck connecting
to an unreachable primary still produces a row and passes the current
test. Testing status = 'streaming' would close that, but every column
except pid is NULL for roles without pg_read_all_stats, so the strict
form only works for privileged users. Which trade-off is preferable? I'd
rather not make the semantics privilege-dependent.

2) Is a separate boolean the right approach, or should this be a new
target_session_attrs value? I went with a separate parameter because
otherwise standby, prefer-standby, read-only and any would each need a
paired variant.

It's important to note that this is a "liveness check", not a freshness
guarantee: a standby that passes may still be far behind in replay, and
a standby recovering only from archive is rejected even if current.

Is this the right direction? Any feedback is much appreciated!

Best, Jim

Attachment Content-Type Size
v1-0001-Add-require_wal_receiver-connection-parameter-to-.patch text/x-patch 31.0 KB

Browse pgsql-hackers by date

  From Date Subject
Previous Message Sami Imseih 2026-09-05 22:09:57 Re: pgstat: Flush some statistics within running transactions, take 2