From 0f3b0256d7cf09d318f12465fe521bb4918a531f Mon Sep 17 00:00:00 2001
From: Vignesh C <vignesh21@gmail.com>
Date: Sat, 11 Jul 2026 12:02:17 +0530
Subject: [PATCH v2 2/3] Reject concurrent sequence refreshes

`ALTER SUBSCRIPTION ... REFRESH SEQUENCES` can race with an already
running sequence synchronization worker. If a second refresh request
resets the synchronization state while the worker has already fetched
sequence values from the publisher but has not yet applied them to the
subscriber, the worker can overwrite the subscriber with stale values
and mark the synchronization as complete.

Avoid this race by rejecting `ALTER SUBSCRIPTION ... REFRESH SEQUENCES`
when a sequence synchronization worker is already running for the
subscription. The command reports an error asking the user to rerun it
after the current synchronization completes.
---
 src/backend/commands/subscriptioncmds.c  | 34 +++++++++++++++++++++---
 src/test/subscription/t/036_sequences.pl |  4 +++
 2 files changed, 34 insertions(+), 4 deletions(-)

diff --git a/src/backend/commands/subscriptioncmds.c b/src/backend/commands/subscriptioncmds.c
index e2a1abfb103..ea8950c70db 100644
--- a/src/backend/commands/subscriptioncmds.c
+++ b/src/backend/commands/subscriptioncmds.c
@@ -1363,6 +1363,32 @@ AlterSubscription_refresh_seq(Subscription *sub)
 	WalReceiverConn *wrconn;
 	bool		must_use_password;
 
+	/*
+	 * Disallow a concurrent REFRESH SEQUENCES while a sequence sync worker
+	 * for this subscription is still running. This avoids a race where the
+	 * publisher's sequence advances after the current worker has fetched its
+	 * value but before it marks the sequence READY. A user may then issue
+	 * another REFRESH SEQUENCES to synchronize the updated value. Since the
+	 * affected sequences are already in the INIT state, the running worker
+	 * has no indication that a new synchronization has been requested. It
+	 * would then apply the stale value it already fetched and mark the
+	 * sequence READY, causing the new synchronization request to be lost and
+	 * preventing the updated publisher values from being synchronized.
+	 */
+	LWLockAcquire(LogicalRepWorkerLock, LW_SHARED);
+	if (logicalrep_worker_find(WORKERTYPE_SEQUENCESYNC, sub->oid, InvalidOid,
+							   true))
+	{
+		LWLockRelease(LogicalRepWorkerLock);
+		ereport(ERROR,
+				errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+				errmsg("cannot execute %s while a sequence synchronization worker for subscription \"%s\" is still running",
+					   "ALTER SUBSCRIPTION ... REFRESH SEQUENCES",
+					   sub->name),
+				errhint("Try again after the current synchronization completes."));
+	}
+	LWLockRelease(LogicalRepWorkerLock);
+
 	/* Load the library providing us libpq calls. */
 	load_file("libpqwalreceiver", false);
 
@@ -1381,10 +1407,10 @@ AlterSubscription_refresh_seq(Subscription *sub)
 		List	   *subrel_states;
 
 		/*
-		 * Sequence synchronization relies on pg_get_sequence_data(), which
-		 * is only available since PostgreSQL 19.  Fail immediately with a
-		 * clear diagnosis instead of resetting the sequences to INIT state
-		 * and letting a sequencesync worker repeatedly fail trying to fetch
+		 * Sequence synchronization relies on pg_get_sequence_data(), which is
+		 * only available since PostgreSQL 19.  Fail immediately with a clear
+		 * diagnosis instead of resetting the sequences to INIT state and
+		 * letting a sequencesync worker repeatedly fail trying to fetch
 		 * sequence data with a query that can never succeed against this
 		 * publisher.
 		 */
diff --git a/src/test/subscription/t/036_sequences.pl b/src/test/subscription/t/036_sequences.pl
index 2a0819aaf01..8b02b24a7e9 100644
--- a/src/test/subscription/t/036_sequences.pl
+++ b/src/test/subscription/t/036_sequences.pl
@@ -232,6 +232,10 @@ $node_publisher->safe_psql(
 	CREATE SEQUENCE regress_s4 START 10 INCREMENT 2;
 ));
 
+# Wait for the missing sequence added to be synced
+$node_subscriber->poll_query_until('postgres', $synced_query)
+  or die "Timed out while waiting for subscriber to synchronize data";
+
 ##########
 # Ensure that insufficient privileges on the publisher for a sequence
 # are reported correctly as a permission issue, not as a missing sequence.
-- 
2.50.1 (Apple Git-155)

