diff --git a/doc/src/sgml/config.sgml b/doc/src/sgml/config.sgml
index 7a48973b3c..f2d4119cce 100644
--- a/doc/src/sgml/config.sgml
+++ b/doc/src/sgml/config.sgml
@@ -4519,9 +4519,12 @@ ANY <replaceable class="parameter">num_sync</replaceable> ( <replaceable class="
         <listitem>
          <para>
           Specifies a trigger file whose presence ends recovery in the
-          standby.  Even if this value is not set, you can still promote
-          the standby using <command>pg_ctl promote</command> or calling
-          <function>pg_promote()</function>.
+          standby, though this may take as long as 300s to take effect.
+          This mechanism is now deprecated and will be removed in a later
+          release. The preferred mechanism by which to promote the standby 
+          is by using <command>pg_ctl promote</command> or calling
+          <function>pg_promote()</function>, both of which promote much
+          faster than using this parameter.
           This parameter can only be set in the <filename>postgresql.conf</filename>
           file or on the server command line.
          </para>
diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml
index 81fa26f985..9174dc9318 100644
--- a/doc/src/sgml/high-availability.sgml
+++ b/doc/src/sgml/high-availability.sgml
@@ -653,11 +653,11 @@ protocol to make nodes agree on a serializable transactional order.
 
    <para>
     Standby mode is exited and the server switches to normal operation
-    when <command>pg_ctl promote</command> is run,
-    <function>pg_promote()</function> is called, or a trigger file is found
-    (<varname>promote_trigger_file</varname>). Before failover,
-    any WAL immediately available in the archive or in <filename>pg_wal</filename> will be
-    restored, but no attempt is made to connect to the primary.
+    when <command>pg_ctl promote</command> is run, or
+    <function>pg_promote()</function> is called.  Use of
+    <varname>promote_trigger_file</varname> is deprecated. Before failover,
+    any WAL immediately available in the archive or in <filename>pg_wal</filename>
+    will be restored, but no attempt is made to connect to the primary.
    </para>
   </sect2>
 
@@ -1483,12 +1483,8 @@ synchronous_standby_names = 'ANY 2 (s1, s2, s3)'
 
    <para>
     To trigger failover of a log-shipping standby server, run
-    <command>pg_ctl promote</command>, call <function>pg_promote()</function>,
-    or create a trigger file with the file name and path specified by the
-    <varname>promote_trigger_file</varname>. If you're planning to use
-    <command>pg_ctl promote</command> or to call
-    <function>pg_promote()</function> to fail over,
-    <varname>promote_trigger_file</varname> is not required. If you're
+    <command>pg_ctl promote</command> or call <function>pg_promote()</function>.
+    Use of <varname>promote_trigger_file</varname> is deprecated. If you're
     setting up the reporting servers that are only used to offload read-only
     queries from the primary, not for high availability purposes, you don't
     need to promote it.
diff --git a/src/backend/access/transam/xlogrecovery.c b/src/backend/access/transam/xlogrecovery.c
index 9feea3e6ec..1eadc448a6 100644
--- a/src/backend/access/transam/xlogrecovery.c
+++ b/src/backend/access/transam/xlogrecovery.c
@@ -3709,14 +3709,17 @@ WaitForWALToBecomeAvailable(XLogRecPtr RecPtr, bool randAccess,
 					}
 
 					/*
-					 * Wait for more WAL to arrive. Time out after 5 seconds
-					 * to react to a trigger file promptly and to check if the
-					 * WAL receiver is still active.
+					 * Wait for more WAL to arrive, when we will be woken
+					 * immediately by the WAL receiver.  Hibernate, but time out
+					 * to react to a trigger file.  Direct use of trigger file
+					 * is now deprecated and the promote_trigger_file will be
+					 * removed in a later use.
 					 */
 					(void) WaitLatch(&XLogRecoveryCtl->recoveryWakeupLatch,
 									 WL_LATCH_SET | WL_TIMEOUT |
 									 WL_EXIT_ON_PM_DEATH,
-									 5000L, WAIT_EVENT_RECOVERY_WAL_STREAM);
+									 HIBERNATE_DELAY_MS,
+									 WAIT_EVENT_RECOVERY_WAL_STREAM);
 					ResetLatch(&XLogRecoveryCtl->recoveryWakeupLatch);
 					break;
 				}
diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c
index 681ef91b81..942cc4a07f 100644
--- a/src/backend/postmaster/autovacuum.c
+++ b/src/backend/postmaster/autovacuum.c
@@ -134,7 +134,6 @@ int			Log_autovacuum_min_duration = 600000;
 
 /* the minimum allowed time between two awakenings of the launcher */
 #define MIN_AUTOVAC_SLEEPTIME 100.0 /* milliseconds */
-#define MAX_AUTOVAC_SLEEPTIME 300	/* seconds */
 
 /* Flags to tell if we are in an autovacuum process */
 static bool am_autovacuum_launcher = false;
@@ -932,8 +931,8 @@ launcher_determine_sleep(bool canlaunch, bool recursing, struct timeval *nap)
 	 * infinite sleep in strange cases like the system clock going backwards a
 	 * few years.
 	 */
-	if (nap->tv_sec > MAX_AUTOVAC_SLEEPTIME)
-		nap->tv_sec = MAX_AUTOVAC_SLEEPTIME;
+	if (nap->tv_sec > HIBERNATE_DELAY_SEC)
+		nap->tv_sec = HIBERNATE_DELAY_SEC;
 }
 
 /*
diff --git a/src/backend/postmaster/bgwriter.c b/src/backend/postmaster/bgwriter.c
index d1f5d12eff..9566fd2b3d 100644
--- a/src/backend/postmaster/bgwriter.c
+++ b/src/backend/postmaster/bgwriter.c
@@ -60,12 +60,6 @@
  */
 int			BgWriterDelay = 200;
 
-/*
- * Multiplier to apply to BgWriterDelay when we decide to hibernate.
- * (Perhaps this needs to be configurable?)
- */
-#define HIBERNATE_FACTOR			50
-
 /*
  * Interval in which standby snapshots are logged into the WAL stream, in
  * milliseconds.
@@ -337,7 +331,7 @@ BackgroundWriterMain(void)
 			/* Sleep ... */
 			(void) WaitLatch(MyLatch,
 							 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
-							 BgWriterDelay * HIBERNATE_FACTOR,
+							 HIBERNATE_DELAY_MS,
 							 WAIT_EVENT_BGWRITER_HIBERNATE);
 			/* Reset the notification request in case we timed out */
 			StrategyNotifyBgWriter(-1);
diff --git a/src/backend/postmaster/pgarch.c b/src/backend/postmaster/pgarch.c
index d916ed39a8..156a4b6404 100644
--- a/src/backend/postmaster/pgarch.c
+++ b/src/backend/postmaster/pgarch.c
@@ -53,8 +53,6 @@
  * Timer definitions.
  * ----------
  */
-#define PGARCH_AUTOWAKE_INTERVAL 60 /* How often to force a poll of the
-									 * archive status directory; in seconds. */
 #define PGARCH_RESTART_INTERVAL 10	/* How often to attempt to restart a
 									 * failed archiver; in seconds. */
 
@@ -346,7 +344,7 @@ pgarch_MainLoop(void)
 
 		/*
 		 * Sleep until a signal is received, or until a poll is forced by
-		 * PGARCH_AUTOWAKE_INTERVAL having passed since last_copy_time, or
+		 * HIBERNATE_DELAY_SEC having passed since last_copy_time, or
 		 * until postmaster dies.
 		 */
 		if (!time_to_stop)		/* Don't wait during last iteration */
@@ -354,7 +352,7 @@ pgarch_MainLoop(void)
 			pg_time_t	curtime = (pg_time_t) time(NULL);
 			int			timeout;
 
-			timeout = PGARCH_AUTOWAKE_INTERVAL - (curtime - last_copy_time);
+			timeout = HIBERNATE_DELAY_SEC - (curtime - last_copy_time);
 			if (timeout > 0)
 			{
 				int			rc;
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index 80bb269599..e998896917 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -1637,7 +1637,7 @@ DetermineSleepTime(struct timeval *timeout)
 		}
 		else
 		{
-			timeout->tv_sec = 60;
+			timeout->tv_sec = HIBERNATE_DELAY_SEC;
 			timeout->tv_usec = 0;
 		}
 		return;
@@ -1695,15 +1695,15 @@ DetermineSleepTime(struct timeval *timeout)
 		timeout->tv_usec = microsecs;
 
 		/* Ensure we don't exceed one minute */
-		if (timeout->tv_sec > 60)
+		if (timeout->tv_sec > HIBERNATE_DELAY_SEC)
 		{
-			timeout->tv_sec = 60;
+			timeout->tv_sec = HIBERNATE_DELAY_SEC;
 			timeout->tv_usec = 0;
 		}
 	}
 	else
 	{
-		timeout->tv_sec = 60;
+		timeout->tv_sec = HIBERNATE_DELAY_SEC;
 		timeout->tv_usec = 0;
 	}
 }
diff --git a/src/backend/postmaster/walwriter.c b/src/backend/postmaster/walwriter.c
index 102fa2a089..7f0b74d0de 100644
--- a/src/backend/postmaster/walwriter.c
+++ b/src/backend/postmaster/walwriter.c
@@ -70,13 +70,7 @@
 int			WalWriterDelay = 200;
 int			WalWriterFlushAfter = 128;
 
-/*
- * Number of do-nothing loops before lengthening the delay time, and the
- * multiplier to apply to WalWriterDelay when we do decide to hibernate.
- * (Perhaps these need to be configurable?)
- */
-#define LOOPS_UNTIL_HIBERNATE		50
-#define HIBERNATE_FACTOR			25
+DECLARE_HIBERNATE_VARS();
 
 /* Prototypes for private functions */
 static void HandleWalWriterInterrupts(void);
@@ -210,7 +204,7 @@ WalWriterMain(void)
 	/*
 	 * Reset hibernation state after any error.
 	 */
-	left_till_hibernate = LOOPS_UNTIL_HIBERNATE;
+	RESET_TO_NON_HIBERNATE();
 	hibernating = false;
 	SetWalWriterSleeping(false);
 
@@ -225,8 +219,6 @@ WalWriterMain(void)
 	 */
 	for (;;)
 	{
-		long		cur_timeout;
-
 		/*
 		 * Advertise whether we might hibernate in this cycle.  We do this
 		 * before resetting the latch to ensure that any async commits will
@@ -252,24 +244,11 @@ WalWriterMain(void)
 		 * Do what we're here for; then, if XLogBackgroundFlush() found useful
 		 * work to do, reset hibernation counter.
 		 */
-		if (XLogBackgroundFlush())
-			left_till_hibernate = LOOPS_UNTIL_HIBERNATE;
-		else if (left_till_hibernate > 0)
-			left_till_hibernate--;
+		SET_DELAY_OR_HIBERNATE(XLogBackgroundFlush(), WalWriterDelay);
 
 		/* Send WAL statistics to the stats collector */
 		pgstat_send_wal(false);
 
-		/*
-		 * Sleep until we are signaled or WalWriterDelay has elapsed.  If we
-		 * haven't done anything useful for quite some time, lengthen the
-		 * sleep time so as to reduce the server's idle power consumption.
-		 */
-		if (left_till_hibernate > 0)
-			cur_timeout = WalWriterDelay;	/* in ms */
-		else
-			cur_timeout = WalWriterDelay * HIBERNATE_FACTOR;
-
 		(void) WaitLatch(MyLatch,
 						 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
 						 cur_timeout,
diff --git a/src/backend/replication/logical/launcher.c b/src/backend/replication/logical/launcher.c
index 6f25b2c2ad..6ae178c1a7 100644
--- a/src/backend/replication/logical/launcher.c
+++ b/src/backend/replication/logical/launcher.c
@@ -48,9 +48,6 @@
 #include "utils/snapmgr.h"
 #include "utils/timeout.h"
 
-/* max sleep time between cycles (3min) */
-#define DEFAULT_NAPTIME_PER_CYCLE 180000L
-
 int			max_logical_replication_workers = 4;
 int			max_sync_workers_per_subscription = 2;
 
@@ -802,6 +799,7 @@ void
 ApplyLauncherMain(Datum main_arg)
 {
 	TimestampTz last_start_time = 0;
+	DECLARE_HIBERNATE_VARS();
 
 	ereport(DEBUG1,
 			(errmsg_internal("logical replication launcher started")));
@@ -831,11 +829,12 @@ ApplyLauncherMain(Datum main_arg)
 		MemoryContext subctx;
 		MemoryContext oldctx;
 		TimestampTz now;
-		long		wait_time = DEFAULT_NAPTIME_PER_CYCLE;
+		bool		work_done;
 
 		CHECK_FOR_INTERRUPTS();
 
 		now = GetCurrentTimestamp();
+		work_done = false;
 
 		/* Limit the start retry to once a wal_retrieve_retry_interval */
 		if (TimestampDifferenceExceeds(last_start_time, now,
@@ -866,7 +865,7 @@ ApplyLauncherMain(Datum main_arg)
 				if (w == NULL)
 				{
 					last_start_time = now;
-					wait_time = wal_retrieve_retry_interval;
+					work_done = true;
 
 					logicalrep_worker_launch(sub->dbid, sub->oid, sub->name,
 											 sub->owner, InvalidOid);
@@ -886,13 +885,16 @@ ApplyLauncherMain(Datum main_arg)
 			 * usually means crash of the worker, so we should retry in
 			 * wal_retrieve_retry_interval again.
 			 */
-			wait_time = wal_retrieve_retry_interval;
+			work_done = true;
 		}
 
+		SET_DELAY_OR_HIBERNATE(work_done,
+							   wal_retrieve_retry_interval);
+
 		/* Wait for more work. */
 		rc = WaitLatch(MyLatch,
 					   WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
-					   wait_time,
+					   cur_timeout,
 					   WAIT_EVENT_LOGICAL_LAUNCHER_MAIN);
 
 		if (rc & WL_LATCH_SET)
diff --git a/src/backend/replication/logical/worker.c b/src/backend/replication/logical/worker.c
index 82dcffc2db..deb4ed0583 100644
--- a/src/backend/replication/logical/worker.c
+++ b/src/backend/replication/logical/worker.c
@@ -196,8 +196,6 @@
 #include "utils/syscache.h"
 #include "utils/timeout.h"
 
-#define NAPTIME_PER_CYCLE 1000	/* max sleep time between cycles (1s) */
-
 typedef struct FlushPosition
 {
 	dlist_node	node;
@@ -2656,6 +2654,7 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
 	bool		ping_sent = false;
 	TimeLineID	tli;
 	ErrorContextCallback errcallback;
+	DECLARE_HIBERNATE_VARS();
 
 	/*
 	 * Init the ApplyMessageContext which we clean up after each replication
@@ -2692,7 +2691,6 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
 		int			len;
 		char	   *buf = NULL;
 		bool		endofstream = false;
-		long		wait_time;
 
 		CHECK_FOR_INTERRUPTS();
 
@@ -2726,6 +2724,7 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
 					/* Reset timeout. */
 					last_recv_timestamp = GetCurrentTimestamp();
 					ping_sent = false;
+					RESET_TO_NON_HIBERNATE();
 
 					/* Ensure we are reading the data into our memory context. */
 					MemoryContextSwitchTo(ApplyMessageContext);
@@ -2814,15 +2813,15 @@ LogicalRepApplyLoop(XLogRecPtr last_received)
 		 * no particular urgency about waking up unless we get data or a
 		 * signal.
 		 */
-		if (!dlist_is_empty(&lsn_mapping))
-			wait_time = WalWriterDelay;
-		else
-			wait_time = NAPTIME_PER_CYCLE;
+		SET_DELAY_OR_HIBERNATE_OPT(!dlist_is_empty(&lsn_mapping),
+									WalWriterDelay,
+									wal_receiver_timeout / 2);
 
 		rc = WaitLatchOrSocket(MyLatch,
 							   WL_SOCKET_READABLE | WL_LATCH_SET |
 							   WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
-							   fd, wait_time,
+							   fd,
+							   cur_timeout,
 							   WAIT_EVENT_LOGICAL_APPLY_MAIN);
 
 		if (rc & WL_LATCH_SET)
diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c
index ceaff097b9..f351038aca 100644
--- a/src/backend/replication/walreceiver.c
+++ b/src/backend/replication/walreceiver.c
@@ -95,7 +95,7 @@ bool		hot_standby_feedback;
 static WalReceiverConn *wrconn = NULL;
 WalReceiverFunctionsType *WalReceiverFunctions = NULL;
 
-#define NAPTIME_PER_CYCLE 100	/* max sleep time between cycles (100ms) */
+#define WALRECEIVER_WAIT_PER_CYCLE 100L	/* normal sleep time between cycles (100ms) */
 
 /*
  * These variables are used similarly to openLogFile/SegNo,
@@ -513,7 +513,7 @@ WalReceiverMain(void)
 									   WL_EXIT_ON_PM_DEATH | WL_SOCKET_READABLE |
 									   WL_TIMEOUT | WL_LATCH_SET,
 									   wait_fd,
-									   NAPTIME_PER_CYCLE,
+									   wal_receiver_timeout / 2,
 									   WAIT_EVENT_WAL_RECEIVER_MAIN);
 				if (rc & WL_LATCH_SET)
 				{
diff --git a/src/backend/replication/walreceiverfuncs.c b/src/backend/replication/walreceiverfuncs.c
index 90798b9d53..dfb2d9836b 100644
--- a/src/backend/replication/walreceiverfuncs.c
+++ b/src/backend/replication/walreceiverfuncs.c
@@ -33,12 +33,6 @@
 
 WalRcvData *WalRcv = NULL;
 
-/*
- * How long to wait for walreceiver to start up after requesting
- * postmaster to launch it. In seconds.
- */
-#define WALRCV_STARTUP_TIMEOUT 10
-
 /* Report shared memory space needed by WalRcvShmemInit */
 Size
 WalRcvShmemSize(void)
@@ -96,7 +90,7 @@ WalRcvRunning(void)
 	{
 		pg_time_t	now = (pg_time_t) time(NULL);
 
-		if ((now - startTime) > WALRCV_STARTUP_TIMEOUT)
+		if ((now - startTime) > wal_receiver_timeout)
 		{
 			bool		stopped = false;
 
@@ -147,7 +141,7 @@ WalRcvStreaming(void)
 	{
 		pg_time_t	now = (pg_time_t) time(NULL);
 
-		if ((now - startTime) > WALRCV_STARTUP_TIMEOUT)
+		if ((now - startTime) > wal_receiver_timeout)
 		{
 			bool		stopped = false;
 
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 932aefc777..f42bd18aa2 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -3995,7 +3995,8 @@ static struct config_string ConfigureNamesString[] =
 	{
 		{"promote_trigger_file", PGC_SIGHUP, REPLICATION_STANDBY,
 			gettext_noop("Specifies a file name whose presence ends recovery in the standby."),
-			NULL
+			NULL,
+			GUC_NOT_IN_SAMPLE
 		},
 		&PromoteTriggerFile,
 		"",
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 4cf5b26a36..e61a361e80 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -325,7 +325,6 @@
 
 #primary_conninfo = ''			# connection string to sending server
 #primary_slot_name = ''			# replication slot on sending server
-#promote_trigger_file = ''		# file name whose presence ends recovery
 #hot_standby = on			# "off" disallows queries during recovery
 					# (change requires restart)
 #max_standby_archive_delay = 30s	# max delay before canceling queries
diff --git a/src/include/storage/latch.h b/src/include/storage/latch.h
index 0dd79d73fa..4301f189f5 100644
--- a/src/include/storage/latch.h
+++ b/src/include/storage/latch.h
@@ -83,6 +83,30 @@
  * only, so using any latch other than the process latch effectively precludes
  * use of any generic handler.
  *
+ * Since not all servers have a 24/7 duty cycle, if a worker has no current
+ * work then it can be enhanced to eventually hibernate. The goal here is
+ * to reduce the CPU wakeups and thus reduce electrical power consumption,
+ * making a small contribution to reducing global warming. To support
+ * hibernation, we add some additional macros to judge when, and if, to
+ * switch from a normal loop wait to hibernate timeout.
+ * Using these macros helps have a common design pattern for hibernation.
+ * 1. Add in DECLARE_HIBERNATE_VARS(); to add private vars to this module
+ * 2. Add SET_DELAY_OR_HIBERNATE() to eventually hibernate if idle
+ * 3. Use the variable "curr_timeout" in WaitLatch()
+ * Hibernation for this worker is independent of any other worker.
+ *
+ * #define	normal_wait_timeout_ms = 100L;
+ * DECLARE_HIBERNATE_VARS();
+ * for (;;)
+ * {
+ *	   if (work to do)
+ *		   Do Stuff(); // in particular, exit loop if some condition satisfied
+ *     SET_DELAY_OR_HIBERNATE(work_to_do, normal_wait_timeout_ms);
+ *	   WaitLatch(cur_timeout);
+ *	   ResetLatch();
+ * }
+ * A working example is shown in src/test/modules/worker_spi/worker_spi.c
+ * as well as in code for workers in src/backend/postmaster et al.
  *
  * WaitEventSets allow to wait for latches being set and additional events -
  * postmaster dying and socket readiness of several sockets currently - at the
@@ -140,6 +164,51 @@ typedef struct Latch
 							 WL_SOCKET_CONNECTED | \
 							 WL_SOCKET_CLOSED)
 
+/*
+ * Common design pattern for Hibernation.
+ *
+ * Sleep until we are signaled or normal_delay has elapsed.  If we
+ * haven't done any work for quite some time, lengthen the sleep
+ * time so as to reduce the server's idle power consumption.
+ *
+ * Avoids use static vars to allow each process to
+ * have its own private, independent counters.
+ */
+
+#define HIBERNATE_DELAY_SEC		300
+#define HIBERNATE_DELAY_MS		(1000L * HIBERNATE_DELAY_SEC)
+#define LOOPS_UNTIL_HIBERNATE	50
+
+#define	SET_DELAY_OR_HIBERNATE(work_done, normal_delay)	\
+	if (work_done)									\
+		left_till_hibernate = LOOPS_UNTIL_HIBERNATE;\
+	else if (left_till_hibernate > 0)				\
+		left_till_hibernate--;						\
+	if (left_till_hibernate > 0)					\
+		cur_timeout = normal_delay;					\
+	else											\
+		cur_timeout = HIBERNATE_DELAY_MS;
+
+#define	SET_DELAY_OR_HIBERNATE_OPT(work_done, normal_delay, hib_delay) \
+	if (work_done)									\
+		left_till_hibernate = LOOPS_UNTIL_HIBERNATE;\
+	else if (left_till_hibernate > 0)				\
+		left_till_hibernate--;						\
+	if (left_till_hibernate > 0)					\
+		cur_timeout = normal_delay;					\
+	else											\
+		cur_timeout = hib_delay;
+
+#define AM_HIBERNATING()	(left_till_hibernate == 0)
+
+#define DECLARE_HIBERNATE_VARS()					\
+int		left_till_hibernate = LOOPS_UNTIL_HIBERNATE;\
+long	cur_timeout;
+
+#define RESET_TO_NON_HIBERNATE()					\
+		left_till_hibernate = LOOPS_UNTIL_HIBERNATE;
+
+
 typedef struct WaitEvent
 {
 	int			pos;			/* position in the event data structure */
diff --git a/src/test/modules/worker_spi/worker_spi.c b/src/test/modules/worker_spi/worker_spi.c
index 48829df29c..fd907a6511 100644
--- a/src/test/modules/worker_spi/worker_spi.c
+++ b/src/test/modules/worker_spi/worker_spi.c
@@ -46,6 +46,8 @@ PG_MODULE_MAGIC;
 
 PG_FUNCTION_INFO_V1(worker_spi_launch);
 
+DECLARE_HIBERNATE_VARS();
+
 void		_PG_init(void);
 void		worker_spi_main(Datum) pg_attribute_noreturn();
 
@@ -137,6 +139,7 @@ worker_spi_main(Datum main_arg)
 	worktable  *table;
 	StringInfoData buf;
 	char		name[20];
+	bool		work_done = true;
 
 	table = palloc(sizeof(worktable));
 	sprintf(name, "schema%d", index);
@@ -191,6 +194,13 @@ worker_spi_main(Datum main_arg)
 	{
 		int			ret;
 
+		/*
+		 * Use the standard design pattern for wait time/hibernation.
+		 * After 50 consecutive loops with work_done=false the wait time
+		 * will be set to the standard hibernation timeout.
+		 */
+		SET_DELAY_OR_HIBERNATE(work_done, worker_spi_naptime * 1000L);
+
 		/*
 		 * Background workers mustn't call usleep() or any direct equivalent:
 		 * instead, they may wait on their process latch, which sleeps as
@@ -199,7 +209,7 @@ worker_spi_main(Datum main_arg)
 		 */
 		(void) WaitLatch(MyLatch,
 						 WL_LATCH_SET | WL_TIMEOUT | WL_EXIT_ON_PM_DEATH,
-						 worker_spi_naptime * 1000L,
+						 cur_timeout,
 						 PG_WAIT_EXTENSION);
 		ResetLatch(MyLatch);
 
@@ -256,7 +266,10 @@ worker_spi_main(Datum main_arg)
 				elog(LOG, "%s: count in %s.%s is now %d",
 					 MyBgworkerEntry->bgw_name,
 					 table->schema, table->name, val);
+			work_done = true;
 		}
+		else
+			work_done = false;
 
 		/*
 		 * And finish our transaction.
