Skip to content

Commit bef0667

Browse files
committed
feat: allow reconfiguring pg_net w/o a db restart
Otherwise changing a pg_net config requires a restart of the whole database cluster.
1 parent 94b3358 commit bef0667

File tree

6 files changed

+56
-19
lines changed

6 files changed

+56
-19
lines changed

README.md

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -137,32 +137,42 @@ create extension pg_net;
137137

138138
---
139139

140-
# Extension Configuration:
140+
# Extension Configuration
141141

142142
the extension creates 3 configurable variables:
143143

144144
1. **pg_net.batch_size** _(default: 200)_: An integer that limits the max number of rows that the extension will process from _`net.http_request_queue`_ during each read
145145
2. **pg_net.ttl** _(default: 6 hours)_: An interval that defines the max time a row in the _`net.http_response`_ will live before being deleted
146146
3. **pg_net.database_name** _(default: 'postgres')_: A string that defines which database the extension is applied to
147147

148-
All these variables can be viewed with the following command:
148+
All these variables can be viewed with the following commands:
149149
```sql
150-
select * from pg_settings WHERE name LIKE 'pg_net%'
150+
show pg_net.batch_size;
151+
show pg_net.ttl;
152+
show pg_net.database_name;
151153
```
152154

153-
The postgres.conf file can be found with the following SQL command:
154-
```sql
155-
SHOW config_file;
155+
You can change these by editing the `postgresql.conf` file (find it with `SHOW config_file;`) or with `ALTER SYSTEM`:
156+
157+
```
158+
alter system set pg_net.ttl to '1 hour'
159+
alter system set pg_net.batch_size to 500;
160+
```
161+
162+
Then, reload the settings and restart the `pg_net` background worker with:
163+
156164
```
165+
select net.worker_restart();
166+
```
167+
168+
Note that doing `ALTER SYSTEM` requires SUPERUSER but on PostgreSQL >= 15, you can do:
157169

158-
You can change the variables by adding any of the following line to your postgres.conf file
159170
```
160-
pg_net.batch_size = <new integer>
161-
pg_net.ttl = '<new ttl interval>'
162-
pg_net.database_name = '<database name>'
171+
grant alter system on parameter pg_net.ttl to <role>;
172+
grant alter system on parameter pg_net.batch_size to <role>;
163173
```
164174

165-
After saving the file, you can execute `SELECT pg_reload_conf()` to update _postgres.conf_ for your database. If the extension does not respond to the update, it may be necessary to restart your database.
175+
To allow regular users to update `pg_net` settings.
166176

167177
# Requests API
168178

nix/pgScript.nix

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ let
2222
2323
options="-F -c listen_addresses=\"\" -c log_min_messages=${logMin} -k $PGDATA"
2424
25-
ext_options="-c shared_preload_libraries=\"pg_net\" -c pg_net.ttl=\"4 seconds\""
25+
ext_options="-c shared_preload_libraries=\"pg_net\""
2626
2727
pg_ctl start -o "$options" -o "$ext_options"
2828

sql/pg_net.sql

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,5 +353,14 @@ begin
353353
end;
354354
$$;
355355

356+
create or replace function net.worker_restart() returns bool as $$
357+
select pg_reload_conf();
358+
select pg_terminate_backend(pid)
359+
from pg_stat_activity
360+
where backend_type ilike '%pg_net%';
361+
$$
362+
security definer
363+
language sql;
364+
356365
grant all on schema net to postgres;
357366
grant all on all tables in schema net to postgres;

src/worker.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ PG_MODULE_MAGIC;
3636

3737
static char *ttl = "6 hours";
3838
static int batch_size = 500;
39-
char* database_name = "postgres";
39+
static char* database_name = "postgres";
4040

4141
void _PG_init(void);
4242
PGDLLEXPORT void worker_main(Datum main_arg) pg_attribute_noreturn();
@@ -181,6 +181,8 @@ worker_main(Datum main_arg)
181181

182182
BackgroundWorkerInitializeConnection(database_name, NULL, 0);
183183

184+
elog(INFO, "pg_net worker started with a config of: pg_net.ttl=%s, pg_net.batch_size=%d, pg_net.database_name=%s", ttl, batch_size, database_name);
185+
184186
while (!got_sigterm)
185187
{
186188
WaitLatch(&MyProc->procLatch,
@@ -430,7 +432,8 @@ worker_main(Datum main_arg)
430432
CommitTransactionCommand();
431433
}
432434

433-
proc_exit(0);
435+
// causing a failure on exit will make the postmaster process restart the bg worker
436+
proc_exit(EXIT_FAILURE);
434437
}
435438

436439
void
@@ -454,7 +457,7 @@ _PG_init(void)
454457
snprintf(worker.bgw_library_name, BGW_MAXLEN, "pg_net");
455458
snprintf(worker.bgw_function_name, BGW_MAXLEN, "worker_main");
456459
snprintf(worker.bgw_name, BGW_MAXLEN, "pg_net " EXTVERSION " worker");
457-
worker.bgw_restart_time = 32;
460+
worker.bgw_restart_time = 1;
458461
worker.bgw_main_arg = (Datum) 0;
459462
worker.bgw_notify_pid = 0;
460463
RegisterBackgroundWorker(&worker);
@@ -477,7 +480,7 @@ _PG_init(void)
477480
NULL, NULL, NULL);
478481

479482
DefineCustomStringVariable("pg_net.database_name",
480-
"database where the pg_net worker is connected",
483+
"Database where pg_net tables are located",
481484
NULL,
482485
&database_name,
483486
"postgres",

test/test_http_requests_deleted_after_ttl.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@
55

66
def test_http_requests_deleted_after_ttl(sess):
77
"""Check that http requests are deleted within a few seconds of their ttl"""
8+
9+
# commit to avoid "cannot run inside a transaction block" error, see https://stackoverflow.com/a/75757326/4692662
10+
sess.execute(text("COMMIT"))
11+
sess.execute(text("alter system set pg_net.ttl to '4 seconds'"))
12+
sess.execute(text("select net.worker_restart()"))
13+
14+
# bg worker restarts after 1 second
15+
time.sleep(1)
16+
817
# Create a request
918
(request_id,) = sess.execute(text(
1019
"""
@@ -42,3 +51,10 @@ def test_http_requests_deleted_after_ttl(sess):
4251
).fetchone()
4352
# TODO an ERROR status doesn't seem correct here
4453
assert response[0] == "ERROR"
54+
55+
sess.execute(text("COMMIT"))
56+
sess.execute(text("alter system reset pg_net.ttl"))
57+
sess.execute(text("select net.worker_restart()"))
58+
59+
# wait until the worker has restarted to not affect other tests
60+
time.sleep(1)

test/test_worker_error.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,11 @@ def test_success_when_worker_is_up(sess):
1616
def test_http_get_error_when_worker_down(sess):
1717
"""net.http_get returns an error when pg background worker is down"""
1818

19-
# kill the bg worker manually
2019
sess.execute(text("""
21-
select pg_terminate_backend((select pid from pg_stat_activity where backend_type ilike '%pg_net%'));
20+
select net.worker_restart();
2221
"""))
2322

24-
time.sleep(1);
23+
time.sleep(0.1)
2524

2625
with pytest.raises(Exception) as execinfo:
2726
res = sess.execute(text(

0 commit comments

Comments
 (0)