From edff42cb08bcd18c4e9b593ec23504532f7431f2 Mon Sep 17 00:00:00 2001
From: Baji Shaik <baji.pgdev@gmail.com>
Date: Tue, 12 May 2026 01:27:46 +0000
Subject: [PATCH v2 1/1] Fix REPACK decoding worker not cleaned up on FATAL
 exit

When the launching backend of REPACK (CONCURRENTLY) is terminated
via pg_terminate_backend(), ProcDiePending causes ereport(FATAL)
which bypasses PG_FINALLY blocks.  As a result,
stop_repack_decoding_worker() is never called, leaving the
decoding worker running indefinitely and holding its temporary
replication slot.

Fix by registering a before_shmem_exit callback when the decoding worker
is started.  The callback calls stop_repack_decoding_worker(), which
terminates the worker and waits for it to shut down.  Since
before_shmem_exit runs while shared memory is still attached,
WaitForBackgroundWorkerShutdown() is safe to call at this stage.
---
 src/backend/commands/repack.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/src/backend/commands/repack.c b/src/backend/commands/repack.c
index 860e2aecbe9..5e6494bf561 100644
--- a/src/backend/commands/repack.c
+++ b/src/backend/commands/repack.c
@@ -64,6 +64,7 @@
 #include "pgstat.h"
 #include "replication/logicalrelation.h"
 #include "storage/bufmgr.h"
+#include "storage/ipc.h"
 #include "storage/lmgr.h"
 #include "storage/predicate.h"
 #include "storage/proc.h"
@@ -211,6 +212,7 @@ static Oid	determine_clustered_index(Relation rel, bool usingindex,
 
 static void start_repack_decoding_worker(Oid relid);
 static void stop_repack_decoding_worker(void);
+static void repack_decoding_worker_exit_cleanup(int code, Datum arg);
 static Snapshot get_initial_snapshot(DecodingWorker *worker);
 
 static void ProcessRepackMessage(StringInfo msg);
@@ -3454,6 +3456,8 @@ start_repack_decoding_worker(Oid relid)
 	decoding_worker->seg = seg;
 	decoding_worker->error_mqh = mqh;
 
+	before_shmem_exit(repack_decoding_worker_exit_cleanup, (Datum) 0);
+
 	/*
 	 * The decoding setup must be done before the caller can have XID assigned
 	 * for any reason, otherwise the worker might end up in a deadlock,
@@ -3477,6 +3481,17 @@ start_repack_decoding_worker(Oid relid)
 	ConditionVariableCancelSleep();
 }
 
+/*
+ * before_shmem_exit callback to stop the repack decoding worker.  Needed
+ * because SIGTERM (e.g., pg_terminate_backend) causes a FATAL exit, which
+ * bypasses PG_FINALLY blocks.
+ */
+static void
+repack_decoding_worker_exit_cleanup(int code, Datum arg)
+{
+	stop_repack_decoding_worker();
+}
+
 /*
  * Stop the decoding worker and cleanup the related resources.
  *
-- 
2.50.1 (Apple Git-155)

