Re: Exit walsender before confirming remote flush in logical replication

Chao Li <li.evan.chao@gmail.com>

From: Chao Li <li.evan.chao@gmail.com>
To: Fujii Masao <masao.fujii@gmail.com>
Cc: Andres Freund <andres@anarazel.de>, Andrey Silitskiy <a.silitskiy@postgrespro.ru>, Alexander Korotkov <aekorotkov@gmail.com>, Greg Sabino Mullane <htamfids@gmail.com>, Japin Li <japinli@hotmail.com>, Ronan Dunklau <ronan@dunklau.fr>, Vitaly Davydov <v.davydov@postgrespro.ru>, "Hayato Kuroda (Fujitsu)" <kuroda.hayato@fujitsu.com>, "Takamichi Osumi (Fujitsu)" <osumi.takamichi@fujitsu.com>, "pgsql-hackers@postgresql.org" <pgsql-hackers@postgresql.org>, "sawada.mshk@gmail.com" <sawada.mshk@gmail.com>, "michael@paquier.xyz" <michael@paquier.xyz>, "peter.eisentraut@enterprisedb.com" <peter.eisentraut@enterprisedb.com>, "dilipbalaut@gmail.com" <dilipbalaut@gmail.com>, "amit.kapila16@gmail.com" <amit.kapila16@gmail.com>, Kyotaro Horiguchi <horikyota.ntt@gmail.com>, Peter Smith <smithpb2250@gmail.com>
Date: 2026-04-08T08:38:32Z
Lists: pgsql-hackers

> On Apr 8, 2026, at 16:11, Fujii Masao <masao.fujii@gmail.com> wrote:
> 
> On Wed, Apr 8, 2026 at 4:05 PM Chao Li <li.evan.chao@gmail.com> wrote:
>> I have some CF entries failed on this test case as well, so I tried to look into the problem.
> 
> Thanks for working on this, much appreciated!
> 
> 
>> Once entering WalSndDone(), it might call pg_flush() and get stuck:
>> ```
>>        if (WalSndCaughtUp && sentPtr == replicatedPtr &&
>>                !pq_is_send_pending())
>>        {
>>                QueryCompletion qc;
>> 
>>                /* Inform the standby that XLOG streaming is done */
>>                SetQueryCompletion(&qc, CMDTAG_COPY, 0);
>>                EndCommand(&qc, DestRemote, false);
>>                pq_flush();
>> 
>>                proc_exit(0);
>> ```
>> 
>> And once stuck, it will never get back to WalSndCheckShutdownTimeout(), so the new GUC timeout cannot rescue it.
> 
> pq_flush() is called when WalSndCaughtUp && sentPtr == replicatedPtr
> && !pq_is_send_pending().
> Under these conditions, I was thinking that we can assume the kernel send
> buffer isn't full, so pq_flush() (i.e., the send() call) can copy the data
> without blocking and return immediately.
> 
> I'm not very familiar with FreeBSD, but based on [1], I wonder if this
> assumption may not hold there, and pq_flush() could still block....
> 
> Regards,
> 
> [1] https://man.freebsd.org/cgi/man.cgi?unix(4)#BUFFERING
> 
>> Due  to the local nature of the Unix-domain sockets, they do not imple-
>> ment send buffers.  The send(2) and write(2) families of system calls
>> attempt to write data to the receive buffer of the destination socket.
> 
> -- 
> Fujii Masao

I don’t have a FreeBSD box to verify that directly. But the document you pointed out seems to state explicitly that, on Unix-domain sockets, writes go directly to the peer’s receive buffer. If so, the assumption that “the kernel send buffer isn’t full” no longer really holds on FreeBSD. From this perspective, changing to non-blocking pq_flush_if_writable() makes sense to me.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/







Commits

Same data as JSON: GET /api/v1/messages/:b64id/commits the thread's linked commits as JSON, with link sources. API reference →
  1. Avoid blocking indefinitely while finishing walsender shutdown

  2. Add wal_sender_shutdown_timeout GUC to limit shutdown wait for replication

  3. pg_upgrade: Add --copy option

  4. Prevent possibility of panics during shutdown checkpoint.

  5. Support clean switchover.