PostgreSQL 19 promotion can hang on stuck client writes
A barrier wait added for safer promotion has no upper bound when a backend is blocked sending to a paused or dead client, stalling failover and related operations.
PostgreSQL 19 can hang with no fixed deadline while promoting a standby to primary if any backend is blocked writing to a client that has stopped reading. The same stall hits crash failover, standby replay when the primary creates its first logical decoding slot, and DROP DATABASE on a live primary. PostgreSQL 18.6 completes the same promotion in about a tenth of a second.
The hang traces to a change that makes promotion, and several other operations, wait until every process has absorbed a process-signal barrier. A backend whose send buffer is full never services that barrier while it sits in a client write. A paused client that stays connected can hold promotion indefinitely; if the client vanishes, the wait often ends only when TCP gives up, on the order of a quarter hour under common defaults. With synchronous_commit set to remote_apply, commits on the primary can pile up behind the same backlog. DROP DATABASE has carried a related barrier wait since version 15.
Shihao Zhong reported the promotion failure and showed it is deterministic with a stuck client. Manu identified that client-write interrupt handling only acted on fatal die requests, leaving the barrier pending, and posted a master-oriented fix that introduces a configurable barrier timeout (default 30 seconds, matching max_standby_streaming_delay). After the timeout, only client backends or WAL senders still blocked in ClientWrite are signaled to exit; other waiters are left alone. Separate work documents the 19 behavior and points operators at tcp_user_timeout and wal_level as partial mitigations, while an alternate patch absorbs barriers when a blocked read or write wakes, treating any error from that path as FATAL so it cannot corrupt a half-sent message to the client.
Reviewers including Amit Kapila have pushed the documentation note for the 19 stable line and are weighing the timeout approach for master. The timeout clears the stuck promotion, replay, checksum, and DROP DATABASE cases without terminating idle sessions, sync-rep waiters, or paused COPY FROM STDIN clients, at the cost of waiting the full timeout when a truly stuck writer is in the way. A gray area remains: a session slowly shipping one very large value to a constrained client looks identical to a stopped reader from outside the backend.