Streaming Replication Disconnection Behavior under recovery_min_apply_delay Configuration - Mailing list pgsql-general

From Riku Kashiwaki (Fujitsu)
Subject Streaming Replication Disconnection Behavior under recovery_min_apply_delay Configuration
Date
Msg-id OS3PR01MB63229C46662074838546DF589064A@OS3PR01MB6322.jpnprd01.prod.outlook.com
Whole thread Raw
List pgsql-general
I would like to know the behavior when disconnecting streaming replication.
An attempt was made to disconnect streaming replication from a standby server during streaming replication by using the
ALTERSET command and setting primary _conninfo to an empty string. 
However, we have observed that if recovery_min_apply_delay is set and primary_conninfo is set to an empty string +
reloaded,with some WAL remaining that has been sent to the standby but not yet applied, replication will not break. 

Specifically, the following procedures are used.
environment: Postgres16
 recovery_min_apply_delay= set to 5min
 One Primary, One Standby Streaming Replication Configuration
① primary_conninfo set to an empty string
 #ALTER SET primary_conninfo=''"
② Reload and reload the configuration file
 #pg_ctl reload
③ Ensure replication is not terminated
 #psql -d postgres -p 27500 -c "select * from pg_stat_replication"
   pid | usesysid | usename | application_name | client_addr | client_hostname | client_port | backend_start |
backend_xmin| state | sent_lsn | write_lsn | flush_lsn | replay_lsn | write_lag | flush_lag | replay_lag |
sync_priority| sync_state | reply_time 

---------+----------+---------+------------------+-------------+-----------------+-------------+-------------------------------+--------------+-----------+------------+------------+------------+------------+-----------------+-----------------+-----------------+---------------+------------+-------------------------------
 3707259 | 10 | **** | walreceiver | | | -1 | 2025-**-** **:**:**.*** | | streaming | 0/190047E0 | 0/190047E0 |
0/190047E0| 0/19002840 | 00:00:00.000073 | 00:00:00.000261 | 00:01:16.999715 | 0 | async | 2025-**-** **:**:**.** 
(1 line)

④ Verify replication is finished after 5 minutes
 #psql -d postgres -p 27500 -c "select * from pg_stat_replication"
   pid | usesysid | usename | application_name | client_addr | client_hostname | client_port | backend_start |
backend_xmin| state | sent_lsn | write_lsn | flush_lsn | replay_lsn | write_lag | flush_lag | replay_lag |
sync_priority| sync_state | reply_time 

---------+----------+---------+------------------+-------------+-----------------+-------------+-------------------------------+--------------+-----------+------------+------------+------------+------------+-----------------+-----------------+-----------------+---------------+------------+-------------------------------
(0 lines)
As shown above, walreceiver does not terminate until the time specified by recovery_min_apply_delay has elapsed, even
afterreceiving WAL from the primary. 
When you stop the strep configuration, you don't need to make the data consistent with the primary (make the DB state
equivalentto the primary), and it seems natural that the strep configuration should be disconnected immediately. 
Why doesn't the walreceiver process exit until WAL has been applied?

Also, in the source code of walreceiver (Lines 452 to 491 of walreceiver.c), there is a process to wait for completion
ofWAL reception (* 1), but there is no description of the action to wait for walreceiver to terminate if unapplied WAL
remains.
I would appreciate it if you could tell me where you are waiting for walreceiver to exit.


*1 Details
https://github.com/postgres/postgres/blob/master/src/backend/replication/walreceiver.c

(walreceiver.c)
[Processing to loop until walreceiver ends]
 Defines the endofwal flag used to terminate the walreceiver.
            /* Loop until end-of-streaming or error */
            for (;;)
            {
                char     *buf;
                int            len;
                bool        endofwal = false;
                pgsocket    wait_fd = PGINVALID_SOCKET;
                int            rc;
                TimestampTz nextWakeup;
                long        nap;


[Continuing/terminating walreceiver with reference to the length of unreceived WAL (len)]
 len is assigned the return value of the walrcv_receive function (★).
 walrcv_receive returns the length of WAL that has not yet been received from the primary (or -1 if it has).


            /* See if we can read data immediately */
                len = walrcv_receive(wrconn, &buf, &wait_fd); ★
                if (len != 0)
                {
                    /*
                     * Process the received data, and any subsequent data we
                     * can read without blocking.
                     */
                    for (;;)
                    {
                        if (len > 0)
                        {
                            /*
                             * Something was received from primary, so adjust
                             * the ping and terminate wakeup times.
                             */
                            now = GetCurrentTimestamp();
                            WalRcvComputeNextWakeup(WALRCV_WAKEUP_TERMINATE,
                                                    now);
                            WalRcvComputeNextWakeup(WALRCV_WAKEUP_PING, now);
                            XLogWalRcvProcessMsg(buf[0], &buf[1], len - 1,
                                                 startpointTLI);
                        }
                        else if (len == 0)
                            break;
                        else if (len < 0)
                        {
                            ereport(LOG,
                                    (errmsg("replication terminated by primary server"),
                                     errdetail("End of WAL reached on timeline %u at %X/%X.",
                                               startpointTLI,
                                               LSN_FORMAT_ARGS(LogstreamResult.Write))));
                            endofwal = true;
                            break;
                        }
                        len = walrcv_receive(wrconn, &buf, &wait_fd);
                    }





pgsql-general by date:

Previous
From: postgres@arcict.com
Date:
Subject: Re: Postgres 16 unexpected shutdown
Next
From: Richard Zetterberg
Date:
Subject: Changing a varchar(7) domain into text directly in pg_type