From b816759e78c79600118abb68747003c8f6b915ea Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Wed, 27 Feb 2019 11:29:01 +1300
Subject: [PATCH] Report bgworker launch failure during smart shutdown.

If a smart shutdown has been initiated, bgworkers will never be
launched.  Tell any process that might be waiting for them, so that
(for example) parallel query doesn't wait forever to learn the
fate of the workers it tried to launch.

This means that after a smart shutdown has been initiated (and all
currently running parallel workers are forced to quit), future
parallel query executions will fail with:

  ERROR:  parallel worker failed to initialize

This isn't ideal, but it avoids waiting forever.  In future a more
graceful fix that allows parallel queries to run might be developed.

Author: Thomas Munro
Reported-by: Justin Pryzby
Discussion: https://postgr.es/m/CA%2BhUKGLrJij0BuFtHsMHT4QnLP54Z3S6vGVBCWR8A49%2BNzctCw%40mail.gmail.com
---
 src/backend/postmaster/postmaster.c | 42 +++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index ccea231e98..c67139c7a6 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -5713,6 +5713,28 @@ do_start_bgworker(RegisteredBgWorker *rw)
 	return false;
 }
 
+/*
+ * Are we in a state that allows bgworkers to be launched (eventually), or are
+ * we in the process of shutting down?
+ */
+static bool
+bgworker_can_be_started(void)
+{
+	switch (pmState)
+	{
+		case PM_NO_CHILDREN:
+		case PM_WAIT_DEAD_END:
+		case PM_SHUTDOWN_2:
+		case PM_SHUTDOWN:
+		case PM_WAIT_BACKENDS:
+		case PM_WAIT_READONLY:
+		case PM_WAIT_BACKUP:
+			return false;
+		default:
+			return true;
+	}
+}
+
 /*
  * Does the current postmaster state require starting a worker with the
  * specified start_time?
@@ -5852,6 +5874,26 @@ maybe_start_bgworkers(void)
 			continue;
 		}
 
+		/*
+		 * If we're in the process of shutting down, we can't create any new
+		 * bgworkers.  We'd better tell any process that is waiting for news
+		 * of the bgworker that it will never be launched.
+		 */
+		if (!bgworker_can_be_started())
+		{
+			int			notify_pid;
+
+			notify_pid = rw->rw_worker.bgw_notify_pid;
+
+			ForgetBackgroundWorker(&iter);
+
+			/* Report worker is gone now. */
+			if (notify_pid != 0)
+				kill(notify_pid, SIGUSR1);
+
+			continue;
+		}
+
 		/*
 		 * If this worker has crashed previously, maybe it needs to be
 		 * restarted (unless on registration it specified it doesn't want to
-- 
2.20.1

