Skip to content

Commit 090d0f2

Browse files
committed
Allow discovery of whether a dynamic background worker is running.
Using the infrastructure provided by this patch, it's possible either to wait for the startup of a dynamically-registered background worker, or to poll the status of such a worker without waiting. In either case, the current PID of the worker process can also be obtained. As usual, worker_spi is updated to demonstrate the new functionality. Patch by me. Review by Andres Freund.
1 parent c9e2e2d commit 090d0f2

File tree

12 files changed

+368
-13
lines changed

12 files changed

+368
-13
lines changed

contrib/worker_spi/worker_spi--1.0.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44
\echo Use "CREATE EXTENSION worker_spi" to load this file. \quit
55

66
CREATE FUNCTION worker_spi_launch(pg_catalog.int4)
7-
RETURNS pg_catalog.bool STRICT
7+
RETURNS pg_catalog.int4 STRICT
88
AS 'MODULE_PATHNAME'
99
LANGUAGE C;

contrib/worker_spi/worker_spi.c

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,9 @@ worker_spi_launch(PG_FUNCTION_ARGS)
365365
{
366366
int32 i = PG_GETARG_INT32(0);
367367
BackgroundWorker worker;
368+
BackgroundWorkerHandle *handle;
369+
BgwHandleStatus status;
370+
pid_t pid;
368371

369372
worker.bgw_flags = BGWORKER_SHMEM_ACCESS |
370373
BGWORKER_BACKEND_DATABASE_CONNECTION;
@@ -375,6 +378,25 @@ worker_spi_launch(PG_FUNCTION_ARGS)
375378
sprintf(worker.bgw_function_name, "worker_spi_main");
376379
snprintf(worker.bgw_name, BGW_MAXLEN, "worker %d", i);
377380
worker.bgw_main_arg = Int32GetDatum(i);
378-
379-
PG_RETURN_BOOL(RegisterDynamicBackgroundWorker(&worker));
381+
/* set bgw_notify_pid so that we can use WaitForBackgroundWorkerStartup */
382+
worker.bgw_notify_pid = MyProcPid;
383+
384+
if (!RegisterDynamicBackgroundWorker(&worker, &handle))
385+
PG_RETURN_NULL();
386+
387+
status = WaitForBackgroundWorkerStartup(handle, &pid);
388+
389+
if (status == BGWH_STOPPED)
390+
ereport(ERROR,
391+
(errcode(ERRCODE_INSUFFICIENT_RESOURCES),
392+
errmsg("could not start background process"),
393+
errhint("More details may be available in the server log.")));
394+
if (status == BGWH_POSTMASTER_DIED)
395+
ereport(ERROR,
396+
(errcode(ERRCODE_INSUFFICIENT_RESOURCES),
397+
errmsg("cannot start background processes without postmaster"),
398+
errhint("Kill all remaining database processes and restart the database.")));
399+
Assert(status == BGWH_STARTED);
400+
401+
PG_RETURN_INT32(pid);
380402
}

doc/src/sgml/bgworker.sgml

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@
3737
<function>RegisterBackgroundWorker(<type>BackgroundWorker *worker</type>)</function>
3838
from its <function>_PG_init()</>. Background workers can also be started
3939
after the system is up and running by calling the function
40-
<function>RegisterDynamicBackgroundWorker</function>(<type>BackgroundWorker
41-
*worker</type>). Unlike <function>RegisterBackgroundWorker</>, which can
42-
only be called from within the postmaster,
43-
<function>RegisterDynamicBackgroundWorker</function> must be called from
44-
a regular backend.
40+
<function>RegisterDynamicBackgroundWorker(<type>BackgroundWorker
41+
*worker, BackgroundWorkerHandle **handle</type>)</function>. Unlike
42+
<function>RegisterBackgroundWorker</>, which can only be called from within
43+
the postmaster, <function>RegisterDynamicBackgroundWorker</function> must be
44+
called from a regular backend.
4545
</para>
4646

4747
<para>
@@ -58,6 +58,7 @@ typedef struct BackgroundWorker
5858
char bgw_library_name[BGW_MAXLEN]; /* only if bgw_main is NULL */
5959
char bgw_function_name[BGW_MAXLEN]; /* only if bgw_main is NULL */
6060
Datum bgw_main_arg;
61+
int bgw_notify_pid;
6162
} BackgroundWorker;
6263
</programlisting>
6364
</para>
@@ -135,6 +136,15 @@ typedef struct BackgroundWorker
135136
<structfield>bgw_main</structfield> is NULL.
136137
</para>
137138

139+
<para>
140+
<structfield>bgw_notify_pid</structfield> is the PID of a PostgreSQL
141+
backend process to which the postmaster should send <literal>SIGUSR1</>
142+
when the process is started or exits. It should be 0 for workers registered
143+
at postmaster startup time, or when the backend registering the worker does
144+
not wish to wait for the worker to start up. Otherwise, it should be
145+
initialized to <literal>MyProcPid</>.
146+
</para>
147+
138148
<para>Once running, the process can connect to a database by calling
139149
<function>BackgroundWorkerInitializeConnection(<parameter>char *dbname</parameter>, <parameter>char *username</parameter>)</function>.
140150
This allows the process to run transactions and queries using the
@@ -165,6 +175,40 @@ typedef struct BackgroundWorker
165175
<command>postgres</> itself has terminated.
166176
</para>
167177

178+
<para>
179+
When a background worker is registered using the
180+
<function>RegisterDynamicBackgroundWorker</function> function, it is
181+
possible for the backend performing the registration to obtain information
182+
the status of the worker. Backends wishing to do this should pass the
183+
address of a <type>BackgroundWorkerHandle *</type> as the second argument
184+
to <function>RegisterDynamicBackgroundWorker</function>. If the worker
185+
is successfully registered, this pointer will be initialized with an
186+
opaque handle that can subsequently be passed to
187+
<function>GetBackgroundWorkerPid(<parameter>BackgroundWorkerHandle *</parameter>, <parameter>pid_t *</parameter>)</function>.
188+
This function can be used to poll the status of the worker: a return
189+
value of <literal>BGWH_NOT_YET_STARTED</> indicates that the worker has not
190+
yet been started by the postmaster; <literal>BGWH_STOPPED</literal>
191+
indicates that it has been started but is no longer running; and
192+
<literal>BGWH_STARTED</literal> indicates that it is currently running.
193+
In this last case, the PID will also be returned via the second argument.
194+
</para>
195+
196+
<para>
197+
In some cases, a process which registers a background worker may wish to
198+
wait for the worker to start up. This can be accomplished by initializing
199+
<structfield>bgw_notify_pid</structfield> to <literal>MyProcPid</> and
200+
then passing the <type>BackgroundWorkerHandle *</type> obtained at
201+
registration time to
202+
<function>WaitForBackgroundWorkerStartup(<parameter>BackgroundWorkerHandle
203+
*handle</parameter>, <parameter>pid_t *</parameter>)</function> function.
204+
This function will block until the postmaster has attempted to start the
205+
background worker, or until the postmaster dies. If the background runner
206+
is running, the return value will <literal>BGWH_STARTED</>, and
207+
the PID will be written to the provided address. Otherwise, the return
208+
value will be <literal>BGWH_STOPPED</literal> or
209+
<literal>BGWH_POSTMASTER_DIED</literal>.
210+
</para>
211+
168212
<para>
169213
The <filename>worker_spi</> contrib module contains a working example,
170214
which demonstrates some useful techniques.

src/backend/commands/async.c

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,6 @@ typedef struct QueueBackendStatus
207207
QueuePosition pos; /* backend has read queue up to here */
208208
} QueueBackendStatus;
209209

210-
#define InvalidPid (-1)
211-
212210
/*
213211
* Shared memory state for LISTEN/NOTIFY (excluding its SLRU stuff)
214212
*

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy