@haathie/pgmb 0.2.7 → 0.2.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -10
- package/lib/client.js +16 -9
- package/lib/queries.js +20 -1
- package/package.json +2 -2
- package/sql/pgmb-0.2.0-0.2.8.sql +80 -0
- package/sql/pgmb.sql +90 -35
- package/sql/queries.sql +9 -0
- package/src/client.ts +25 -20
- package/src/queries.ts +60 -0
package/README.md
CHANGED
|
@@ -513,17 +513,13 @@ PGMB relies on 2 functions that need to be run periodically & only once globally
|
|
|
513
513
|
It's okay if this runs simultaneously in multiple processes, but that can create unnecessary contention on the `unread_events` table, which can bubble up to other tables.
|
|
514
514
|
2. `maintain_events_table()` -- removes old partitions & creates new partitions for the events table. It's also okay if this runs simultaneously in multiple processes, as it has advisory locks to ensure only a single process is maintaining the events table at any time, but running this too frequently can cause unnecessary overhead.
|
|
515
515
|
|
|
516
|
-
If you
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
tableMaintainanceMs: 0,
|
|
522
|
-
...otherOpts
|
|
523
|
-
})
|
|
524
|
-
```
|
|
516
|
+
If you have the `pg_cron` extension installed, `pgmb` will automatically setup these functions to run periodically via `pg_cron` on initialization. The default intervals are:
|
|
517
|
+
- `poll_for_events()` -- every `1 second`
|
|
518
|
+
- `maintain_events_table()` -- on every `30th minute`
|
|
519
|
+
|
|
520
|
+
These can be easily configured by changing the values in the `config` table in the `pgmb` schema. Changes automatically get applied to the underlying cron jobs via triggers.
|
|
525
521
|
|
|
526
|
-
|
|
522
|
+
If you do not have `pg_cron` installed, PGMB will run these functions in the same process as the client itself, at the above intervals. This is okay for development & small deployments.
|
|
527
523
|
|
|
528
524
|
## General Notes
|
|
529
525
|
|
package/lib/client.js
CHANGED
|
@@ -63,24 +63,31 @@ class PgmbClient extends batcher_ts_1.PGMBEventBatcher {
|
|
|
63
63
|
if ('connect' in this.client) {
|
|
64
64
|
this.client.on('remove', this.#onPoolClientRemoved);
|
|
65
65
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
const [pgCronRslt] = await queries_ts_1.getConfigValue
|
|
67
|
+
.run({ key: 'use_pg_cron' }, this.client);
|
|
68
|
+
const isPgCronEnabled = pgCronRslt?.value === 'true';
|
|
69
|
+
if (!isPgCronEnabled) {
|
|
70
|
+
// maintain event table
|
|
71
|
+
await queries_ts_1.maintainEventsTable.run(undefined, this.client);
|
|
72
|
+
this.logger.debug('maintained events table');
|
|
73
|
+
if (this.pollEventsIntervalMs) {
|
|
74
|
+
this.#pollTask = this.#startLoop(queries_ts_1.pollForEvents.run.bind(queries_ts_1.pollForEvents, undefined, this.client), this.pollEventsIntervalMs);
|
|
75
|
+
}
|
|
76
|
+
if (this.tableMaintenanceMs) {
|
|
77
|
+
this.#tableMaintainTask = this.#startLoop(queries_ts_1.maintainEventsTable.run
|
|
78
|
+
.bind(queries_ts_1.maintainEventsTable, undefined, this.client), this.tableMaintenanceMs);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
69
81
|
await queries_ts_1.assertGroup.run({ id: this.groupId }, this.client);
|
|
70
82
|
this.logger.debug({ groupId: this.groupId }, 'asserted group exists');
|
|
71
83
|
// clean up expired subscriptions on start
|
|
72
84
|
const [{ deleted }] = await queries_ts_1.removeExpiredSubscriptions.run({ groupId: this.groupId, activeIds: [] }, this.client);
|
|
73
85
|
this.logger.debug({ deleted }, 'removed expired subscriptions');
|
|
74
86
|
this.#readTask = this.#startLoop(this.readChanges.bind(this), this.readEventsIntervalMs);
|
|
75
|
-
if (this.pollEventsIntervalMs) {
|
|
76
|
-
this.#pollTask = this.#startLoop(queries_ts_1.pollForEvents.run.bind(queries_ts_1.pollForEvents, undefined, this.client), this.pollEventsIntervalMs);
|
|
77
|
-
}
|
|
78
87
|
if (this.subscriptionMaintenanceMs) {
|
|
79
88
|
this.#subMaintainTask = this.#startLoop(this.#maintainSubscriptions, this.subscriptionMaintenanceMs);
|
|
80
89
|
}
|
|
81
|
-
|
|
82
|
-
this.#tableMaintainTask = this.#startLoop(queries_ts_1.maintainEventsTable.run.bind(queries_ts_1.maintainEventsTable, undefined, this.client), this.tableMaintenanceMs);
|
|
83
|
-
}
|
|
90
|
+
this.logger.info({ isPgCronEnabled }, 'pgmb client initialised');
|
|
84
91
|
}
|
|
85
92
|
async end() {
|
|
86
93
|
await super.end();
|
package/lib/queries.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.maintainEventsTable = exports.removeExpiredSubscriptions = exports.findEvents = exports.scheduleEventRetry = exports.writeScheduledEvents = exports.writeEvents = exports.releaseGroupLock = exports.setGroupCursor = exports.replayEvents = exports.readNextEventsText = exports.readNextEvents = exports.pollForEvents = exports.markSubscriptionsActive = exports.deleteSubscriptions = exports.assertSubscription = exports.assertGroup = void 0;
|
|
3
|
+
exports.maintainEventsTable = exports.updateConfigValue = exports.getConfigValue = exports.removeExpiredSubscriptions = exports.findEvents = exports.scheduleEventRetry = exports.writeScheduledEvents = exports.writeEvents = exports.releaseGroupLock = exports.setGroupCursor = exports.replayEvents = exports.readNextEventsText = exports.readNextEvents = exports.pollForEvents = exports.markSubscriptionsActive = exports.deleteSubscriptions = exports.assertSubscription = exports.assertGroup = void 0;
|
|
4
4
|
/** Types generated for queries found in "sql/queries.sql" */
|
|
5
5
|
const runtime_1 = require("@pgtyped/runtime");
|
|
6
6
|
const assertGroupIR = { "usedParamSet": { "id": true }, "params": [{ "name": "id", "required": true, "transform": { "type": "scalar" }, "locs": [{ "a": 50, "b": 53 }] }], "statement": "INSERT INTO pgmb.subscription_groups (id)\nVALUES (:id!)\nON CONFLICT DO NOTHING" };
|
|
@@ -225,6 +225,25 @@ const removeExpiredSubscriptionsIR = { "usedParamSet": { "groupId": true, "activ
|
|
|
225
225
|
* ```
|
|
226
226
|
*/
|
|
227
227
|
exports.removeExpiredSubscriptions = new runtime_1.PreparedQuery(removeExpiredSubscriptionsIR);
|
|
228
|
+
const getConfigValueIR = { "usedParamSet": { "key": true }, "params": [{ "name": "key", "required": true, "transform": { "type": "scalar" }, "locs": [{ "a": 29, "b": 33 }] }], "statement": "SELECT pgmb.get_config_value(:key!::pgmb.config_type) AS \"value\"" };
|
|
229
|
+
/**
|
|
230
|
+
* Query generated from SQL:
|
|
231
|
+
* ```
|
|
232
|
+
* SELECT pgmb.get_config_value(:key!::pgmb.config_type) AS "value"
|
|
233
|
+
* ```
|
|
234
|
+
*/
|
|
235
|
+
exports.getConfigValue = new runtime_1.PreparedQuery(getConfigValueIR);
|
|
236
|
+
const updateConfigValueIR = { "usedParamSet": { "value": true, "key": true }, "params": [{ "name": "value", "required": true, "transform": { "type": "scalar" }, "locs": [{ "a": 31, "b": 37 }] }, { "name": "key", "required": true, "transform": { "type": "scalar" }, "locs": [{ "a": 56, "b": 60 }] }], "statement": "UPDATE pgmb.config\nSET value = :value!::TEXT\nWHERE id = :key!::pgmb.config_type\nRETURNING 1 AS \"updated!\"" };
|
|
237
|
+
/**
|
|
238
|
+
* Query generated from SQL:
|
|
239
|
+
* ```
|
|
240
|
+
* UPDATE pgmb.config
|
|
241
|
+
* SET value = :value!::TEXT
|
|
242
|
+
* WHERE id = :key!::pgmb.config_type
|
|
243
|
+
* RETURNING 1 AS "updated!"
|
|
244
|
+
* ```
|
|
245
|
+
*/
|
|
246
|
+
exports.updateConfigValue = new runtime_1.PreparedQuery(updateConfigValueIR);
|
|
228
247
|
const maintainEventsTableIR = { "usedParamSet": {}, "params": [], "statement": "SELECT pgmb.maintain_events_table()" };
|
|
229
248
|
/**
|
|
230
249
|
* Query generated from SQL:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@haathie/pgmb",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.9",
|
|
4
4
|
"description": "PG message broker, with a type-safe typescript client with built-in webhook & SSE support.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"registry": "https://registry.npmjs.org",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"lint": "eslint ./ --ext .js,.ts,.jsx,.tsx",
|
|
22
22
|
"lint:fix": "eslint ./ --fix --ext .js,.ts,.jsx,.tsx",
|
|
23
23
|
"benchmark": "TZ=utc node --env-file ./.env.test src/benchmark/run.ts",
|
|
24
|
-
"
|
|
24
|
+
"pg:typegen": "pgtyped --config ./pgtyped.config.json"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@adiwajshing/eslint-config": "git+https://github.com/adiwajshing/eslint-config",
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
SET search_path TO pgmb;
|
|
2
|
+
|
|
3
|
+
ALTER TYPE config_type ADD VALUE 'use_pg_cron';
|
|
4
|
+
ALTER TYPE config_type ADD VALUE 'pg_cron_poll_for_events_cron';
|
|
5
|
+
ALTER TYPE config_type ADD VALUE 'pg_cron_partition_maintenance_cron';
|
|
6
|
+
|
|
7
|
+
INSERT INTO config(id, value) VALUES
|
|
8
|
+
('pg_cron_poll_for_events_cron', '1 second'),
|
|
9
|
+
-- every 30 minutes
|
|
10
|
+
('pg_cron_partition_maintenance_cron', '*/30 * * * *');
|
|
11
|
+
|
|
12
|
+
CREATE OR REPLACE FUNCTION manage_cron_jobs_trigger_fn()
|
|
13
|
+
RETURNS TRIGGER AS $$
|
|
14
|
+
DECLARE
|
|
15
|
+
poll_job_name CONSTANT TEXT := 'pgmb_poll';
|
|
16
|
+
maintain_job_name CONSTANT TEXT := 'pgmb_maintain_table_partitions';
|
|
17
|
+
BEGIN
|
|
18
|
+
IF get_config_value('use_pg_cron') = 'true' THEN
|
|
19
|
+
-- Schedule/update event polling job
|
|
20
|
+
PERFORM cron.schedule(
|
|
21
|
+
poll_job_name,
|
|
22
|
+
get_config_value('pg_cron_poll_for_events_cron'),
|
|
23
|
+
$CMD$
|
|
24
|
+
-- ensure we don't accidentally run for too long
|
|
25
|
+
SET SESSION statement_timeout = '10s';
|
|
26
|
+
SELECT pgmb.poll_for_events();
|
|
27
|
+
$CMD$
|
|
28
|
+
);
|
|
29
|
+
RAISE LOG 'Scheduled pgmb polling job: %', poll_job_name;
|
|
30
|
+
|
|
31
|
+
-- Schedule/update partition maintenance job
|
|
32
|
+
PERFORM cron.schedule(
|
|
33
|
+
'pgmb_maintain_table_partitions',
|
|
34
|
+
get_config_value('pg_cron_partition_maintenance_cron'),
|
|
35
|
+
$CMD$ SELECT pgmb.maintain_events_table(); $CMD$
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
RAISE LOG 'Scheduled pgmb partition maintenance job: %',
|
|
39
|
+
maintain_job_name;
|
|
40
|
+
ELSIF (SELECT 1 FROM pg_namespace WHERE nspname = 'cron') THEN
|
|
41
|
+
RAISE LOG 'Unscheduling pgmb cron jobs.';
|
|
42
|
+
-- Unschedule jobs. cron.unschedule does not fail if job does not exist.
|
|
43
|
+
PERFORM cron.unschedule(poll_job_name);
|
|
44
|
+
PERFORM cron.unschedule(maintain_job_name);
|
|
45
|
+
END IF;
|
|
46
|
+
|
|
47
|
+
RETURN NULL;
|
|
48
|
+
END;
|
|
49
|
+
$$ LANGUAGE plpgsql VOLATILE PARALLEL UNSAFE SECURITY DEFINER
|
|
50
|
+
SET search_path TO pgmb;
|
|
51
|
+
|
|
52
|
+
CREATE TRIGGER manage_cron_jobs_trigger
|
|
53
|
+
AFTER INSERT OR UPDATE OF value ON config
|
|
54
|
+
FOR EACH ROW
|
|
55
|
+
WHEN (
|
|
56
|
+
NEW.id IN (
|
|
57
|
+
'use_pg_cron',
|
|
58
|
+
'pg_cron_poll_for_events_cron',
|
|
59
|
+
'pg_cron_partition_maintenance_cron'
|
|
60
|
+
)
|
|
61
|
+
)
|
|
62
|
+
EXECUTE FUNCTION manage_cron_jobs_trigger_fn();
|
|
63
|
+
|
|
64
|
+
DO $$
|
|
65
|
+
BEGIN
|
|
66
|
+
IF (
|
|
67
|
+
SELECT EXISTS (
|
|
68
|
+
SELECT 1
|
|
69
|
+
FROM pg_available_extensions
|
|
70
|
+
WHERE name = 'pg_cron'
|
|
71
|
+
)
|
|
72
|
+
) THEN
|
|
73
|
+
CREATE EXTENSION IF NOT EXISTS pg_cron;
|
|
74
|
+
INSERT INTO config(id, value) VALUES ('use_pg_cron', 'true');
|
|
75
|
+
ELSE
|
|
76
|
+
RAISE LOG 'pg_cron extension not available. Skipping pg_cron setup.';
|
|
77
|
+
INSERT INTO config(id, value) VALUES ('use_pg_cron', 'false');
|
|
78
|
+
END IF;
|
|
79
|
+
END
|
|
80
|
+
$$;
|
package/sql/pgmb.sql
CHANGED
|
@@ -22,7 +22,10 @@ CREATE TYPE config_type AS ENUM(
|
|
|
22
22
|
-- how far into the future to create partitions
|
|
23
23
|
'future_intervals_to_create',
|
|
24
24
|
'partition_interval',
|
|
25
|
-
'poll_chunk_size'
|
|
25
|
+
'poll_chunk_size',
|
|
26
|
+
'use_pg_cron',
|
|
27
|
+
'pg_cron_poll_for_events_cron',
|
|
28
|
+
'pg_cron_partition_maintenance_cron'
|
|
26
29
|
);
|
|
27
30
|
|
|
28
31
|
CREATE TABLE IF NOT EXISTS config(
|
|
@@ -37,13 +40,15 @@ CREATE OR REPLACE FUNCTION get_config_value(
|
|
|
37
40
|
SELECT value FROM config WHERE id = config_id
|
|
38
41
|
$$ LANGUAGE sql STRICT STABLE PARALLEL SAFE SET SEARCH_PATH TO pgmb;
|
|
39
42
|
|
|
40
|
-
INSERT INTO config(id, value)
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
INSERT INTO config(id, value) VALUES
|
|
44
|
+
('plugin_version', '0.2.0'),
|
|
45
|
+
('partition_retention_period', '60 minutes'),
|
|
46
|
+
('future_intervals_to_create', '120 minutes'),
|
|
47
|
+
('partition_interval', '30 minutes'),
|
|
48
|
+
('poll_chunk_size', '10000'),
|
|
49
|
+
('pg_cron_poll_for_events_cron', '1 second'),
|
|
50
|
+
-- every 30 minutes
|
|
51
|
+
('pg_cron_partition_maintenance_cron', '*/30 * * * *');
|
|
47
52
|
|
|
48
53
|
-- we'll create the events table next & its functions ---------------
|
|
49
54
|
|
|
@@ -365,33 +370,11 @@ CREATE INDEX ON subscriptions(
|
|
|
365
370
|
add_interval_imm(last_active_at, expiry_interval)
|
|
366
371
|
) WHERE expiry_interval IS NOT NULL;
|
|
367
372
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
SELECT EXISTS (
|
|
374
|
-
SELECT 1
|
|
375
|
-
FROM pg_available_extensions
|
|
376
|
-
WHERE name = 'btree_gin'
|
|
377
|
-
)
|
|
378
|
-
);
|
|
379
|
-
-- create btree_gin extension if not exists, if the extension
|
|
380
|
-
-- is not available, we create a simpler regular GIN index instead.
|
|
381
|
-
IF has_btree_gin THEN
|
|
382
|
-
CREATE EXTENSION IF NOT EXISTS btree_gin;
|
|
383
|
-
-- fastupdate=false, slows down subscription creation, but ensures the costlier
|
|
384
|
-
-- "poll_for_events" function is executed faster.
|
|
385
|
-
CREATE INDEX "sub_gin" ON subscriptions USING GIN(conditions_sql, params)
|
|
386
|
-
WITH (fastupdate = false);
|
|
387
|
-
ELSE
|
|
388
|
-
RAISE NOTICE 'btree_gin extension is not available, using
|
|
389
|
-
regular GIN index for subscriptions.params';
|
|
390
|
-
CREATE INDEX "sub_gin" ON subscriptions USING GIN(params)
|
|
391
|
-
WITH (fastupdate = false);
|
|
392
|
-
END IF;
|
|
393
|
-
END
|
|
394
|
-
$$;
|
|
373
|
+
-- fastupdate=false, slows down subscription creation, but ensures the costlier
|
|
374
|
+
-- "poll_for_events" function is executed faster.
|
|
375
|
+
CREATE EXTENSION IF NOT EXISTS btree_gin;
|
|
376
|
+
CREATE INDEX "sub_gin" ON subscriptions
|
|
377
|
+
USING GIN(conditions_sql, params) WITH (fastupdate = false);
|
|
395
378
|
|
|
396
379
|
-- materialized view to hold distinct conditions_sql statements.
|
|
397
380
|
-- We utilise changes in this view to determine when to prepare the
|
|
@@ -863,6 +846,78 @@ SET search_path TO pgmb;
|
|
|
863
846
|
-- create the initial partitions
|
|
864
847
|
SELECT maintain_events_table();
|
|
865
848
|
|
|
849
|
+
-- setup pg_cron if it's available ----------------
|
|
850
|
+
|
|
851
|
+
CREATE OR REPLACE FUNCTION manage_cron_jobs_trigger_fn()
|
|
852
|
+
RETURNS TRIGGER AS $$
|
|
853
|
+
DECLARE
|
|
854
|
+
poll_job_name CONSTANT TEXT := 'pgmb_poll';
|
|
855
|
+
maintain_job_name CONSTANT TEXT := 'pgmb_maintain_table_partitions';
|
|
856
|
+
BEGIN
|
|
857
|
+
IF get_config_value('use_pg_cron') = 'true' THEN
|
|
858
|
+
-- Schedule/update event polling job
|
|
859
|
+
PERFORM cron.schedule(
|
|
860
|
+
poll_job_name,
|
|
861
|
+
get_config_value('pg_cron_poll_for_events_cron'),
|
|
862
|
+
$CMD$
|
|
863
|
+
-- ensure we don't accidentally run for too long
|
|
864
|
+
SET SESSION statement_timeout = '10s';
|
|
865
|
+
SELECT pgmb.poll_for_events();
|
|
866
|
+
$CMD$
|
|
867
|
+
);
|
|
868
|
+
RAISE LOG 'Scheduled pgmb polling job: %', poll_job_name;
|
|
869
|
+
|
|
870
|
+
-- Schedule/update partition maintenance job
|
|
871
|
+
PERFORM cron.schedule(
|
|
872
|
+
'pgmb_maintain_table_partitions',
|
|
873
|
+
get_config_value('pg_cron_partition_maintenance_cron'),
|
|
874
|
+
$CMD$ SELECT pgmb.maintain_events_table(); $CMD$
|
|
875
|
+
);
|
|
876
|
+
|
|
877
|
+
RAISE LOG 'Scheduled pgmb partition maintenance job: %',
|
|
878
|
+
maintain_job_name;
|
|
879
|
+
ELSIF (SELECT 1 FROM pg_namespace WHERE nspname = 'cron') THEN
|
|
880
|
+
RAISE LOG 'Unscheduling pgmb cron jobs.';
|
|
881
|
+
-- Unschedule jobs. cron.unschedule does not fail if job does not exist.
|
|
882
|
+
PERFORM cron.unschedule(poll_job_name);
|
|
883
|
+
PERFORM cron.unschedule(maintain_job_name);
|
|
884
|
+
END IF;
|
|
885
|
+
|
|
886
|
+
RETURN NULL;
|
|
887
|
+
END;
|
|
888
|
+
$$ LANGUAGE plpgsql VOLATILE PARALLEL UNSAFE SECURITY DEFINER
|
|
889
|
+
SET search_path TO pgmb;
|
|
890
|
+
|
|
891
|
+
CREATE TRIGGER manage_cron_jobs_trigger
|
|
892
|
+
AFTER INSERT OR UPDATE OF value ON config
|
|
893
|
+
FOR EACH ROW
|
|
894
|
+
WHEN (
|
|
895
|
+
NEW.id IN (
|
|
896
|
+
'use_pg_cron',
|
|
897
|
+
'pg_cron_poll_for_events_cron',
|
|
898
|
+
'pg_cron_partition_maintenance_cron'
|
|
899
|
+
)
|
|
900
|
+
)
|
|
901
|
+
EXECUTE FUNCTION manage_cron_jobs_trigger_fn();
|
|
902
|
+
|
|
903
|
+
DO $$
|
|
904
|
+
BEGIN
|
|
905
|
+
IF (
|
|
906
|
+
SELECT EXISTS (
|
|
907
|
+
SELECT 1
|
|
908
|
+
FROM pg_available_extensions
|
|
909
|
+
WHERE name = 'pg_cron'
|
|
910
|
+
)
|
|
911
|
+
) THEN
|
|
912
|
+
CREATE EXTENSION IF NOT EXISTS pg_cron;
|
|
913
|
+
INSERT INTO config(id, value) VALUES ('use_pg_cron', 'true');
|
|
914
|
+
ELSE
|
|
915
|
+
RAISE LOG 'pg_cron extension not available. Skipping pg_cron setup.';
|
|
916
|
+
INSERT INTO config(id, value) VALUES ('use_pg_cron', 'false');
|
|
917
|
+
END IF;
|
|
918
|
+
END
|
|
919
|
+
$$;
|
|
920
|
+
|
|
866
921
|
-- triggers to add events for specific tables ---------------------------
|
|
867
922
|
|
|
868
923
|
-- Function to create a topic string for subscriptions.
|
package/sql/queries.sql
CHANGED
|
@@ -150,5 +150,14 @@ WITH deleted AS (
|
|
|
150
150
|
)
|
|
151
151
|
SELECT COUNT(*) AS "deleted!" FROM deleted;
|
|
152
152
|
|
|
153
|
+
/* @name getConfigValue */
|
|
154
|
+
SELECT pgmb.get_config_value(:key!::pgmb.config_type) AS "value";
|
|
155
|
+
|
|
156
|
+
/* @name updateConfigValue */
|
|
157
|
+
UPDATE pgmb.config
|
|
158
|
+
SET value = :value!::TEXT
|
|
159
|
+
WHERE id = :key!::pgmb.config_type
|
|
160
|
+
RETURNING 1 AS "updated!";
|
|
161
|
+
|
|
153
162
|
/* @name maintainEventsTable */
|
|
154
163
|
SELECT pgmb.maintain_events_table();
|
package/src/client.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
assertGroup,
|
|
8
8
|
assertSubscription,
|
|
9
9
|
deleteSubscriptions,
|
|
10
|
+
getConfigValue,
|
|
10
11
|
maintainEventsTable,
|
|
11
12
|
markSubscriptionsActive,
|
|
12
13
|
pollForEvents,
|
|
@@ -151,9 +152,29 @@ export class PgmbClient<
|
|
|
151
152
|
this.client.on('remove', this.#onPoolClientRemoved)
|
|
152
153
|
}
|
|
153
154
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
155
|
+
const [pgCronRslt] = await getConfigValue
|
|
156
|
+
.run({ key: 'use_pg_cron' }, this.client)
|
|
157
|
+
const isPgCronEnabled = pgCronRslt?.value === 'true'
|
|
158
|
+
if(!isPgCronEnabled) {
|
|
159
|
+
// maintain event table
|
|
160
|
+
await maintainEventsTable.run(undefined, this.client)
|
|
161
|
+
this.logger.debug('maintained events table')
|
|
162
|
+
|
|
163
|
+
if(this.pollEventsIntervalMs) {
|
|
164
|
+
this.#pollTask = this.#startLoop(
|
|
165
|
+
pollForEvents.run.bind(pollForEvents, undefined, this.client),
|
|
166
|
+
this.pollEventsIntervalMs,
|
|
167
|
+
)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if(this.tableMaintenanceMs) {
|
|
171
|
+
this.#tableMaintainTask = this.#startLoop(
|
|
172
|
+
maintainEventsTable.run
|
|
173
|
+
.bind(maintainEventsTable, undefined, this.client),
|
|
174
|
+
this.tableMaintenanceMs,
|
|
175
|
+
)
|
|
176
|
+
}
|
|
177
|
+
}
|
|
157
178
|
|
|
158
179
|
await assertGroup.run({ id: this.groupId }, this.client)
|
|
159
180
|
this.logger.debug({ groupId: this.groupId }, 'asserted group exists')
|
|
@@ -169,13 +190,6 @@ export class PgmbClient<
|
|
|
169
190
|
this.readEventsIntervalMs,
|
|
170
191
|
)
|
|
171
192
|
|
|
172
|
-
if(this.pollEventsIntervalMs) {
|
|
173
|
-
this.#pollTask = this.#startLoop(
|
|
174
|
-
pollForEvents.run.bind(pollForEvents, undefined, this.client),
|
|
175
|
-
this.pollEventsIntervalMs,
|
|
176
|
-
)
|
|
177
|
-
}
|
|
178
|
-
|
|
179
193
|
if(this.subscriptionMaintenanceMs) {
|
|
180
194
|
this.#subMaintainTask = this.#startLoop(
|
|
181
195
|
this.#maintainSubscriptions,
|
|
@@ -183,16 +197,7 @@ export class PgmbClient<
|
|
|
183
197
|
)
|
|
184
198
|
}
|
|
185
199
|
|
|
186
|
-
|
|
187
|
-
this.#tableMaintainTask = this.#startLoop(
|
|
188
|
-
maintainEventsTable.run.bind(
|
|
189
|
-
maintainEventsTable,
|
|
190
|
-
undefined,
|
|
191
|
-
this.client,
|
|
192
|
-
),
|
|
193
|
-
this.tableMaintenanceMs,
|
|
194
|
-
)
|
|
195
|
-
}
|
|
200
|
+
this.logger.info({ isPgCronEnabled }, 'pgmb client initialised')
|
|
196
201
|
}
|
|
197
202
|
|
|
198
203
|
async end() {
|
package/src/queries.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/** Types generated for queries found in "sql/queries.sql" */
|
|
2
2
|
import { PreparedQuery } from '@pgtyped/runtime';
|
|
3
3
|
|
|
4
|
+
export type config_type = 'future_intervals_to_create' | 'partition_interval' | 'partition_retention_period' | 'pg_cron_partition_maintenance_cron' | 'pg_cron_poll_for_events_cron' | 'plugin_version' | 'poll_chunk_size' | 'use_pg_cron';
|
|
5
|
+
|
|
4
6
|
export type DateOrString = Date | string;
|
|
5
7
|
|
|
6
8
|
export type DateOrStringArray = (DateOrString)[];
|
|
@@ -543,6 +545,64 @@ const removeExpiredSubscriptionsIR: any = {"usedParamSet":{"groupId":true,"activ
|
|
|
543
545
|
export const removeExpiredSubscriptions = new PreparedQuery<IRemoveExpiredSubscriptionsParams,IRemoveExpiredSubscriptionsResult>(removeExpiredSubscriptionsIR);
|
|
544
546
|
|
|
545
547
|
|
|
548
|
+
/** 'GetConfigValue' parameters type */
|
|
549
|
+
export interface IGetConfigValueParams {
|
|
550
|
+
key: config_type;
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
/** 'GetConfigValue' return type */
|
|
554
|
+
export interface IGetConfigValueResult {
|
|
555
|
+
value: string | null;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/** 'GetConfigValue' query type */
|
|
559
|
+
export interface IGetConfigValueQuery {
|
|
560
|
+
params: IGetConfigValueParams;
|
|
561
|
+
result: IGetConfigValueResult;
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
const getConfigValueIR: any = {"usedParamSet":{"key":true},"params":[{"name":"key","required":true,"transform":{"type":"scalar"},"locs":[{"a":29,"b":33}]}],"statement":"SELECT pgmb.get_config_value(:key!::pgmb.config_type) AS \"value\""};
|
|
565
|
+
|
|
566
|
+
/**
|
|
567
|
+
* Query generated from SQL:
|
|
568
|
+
* ```
|
|
569
|
+
* SELECT pgmb.get_config_value(:key!::pgmb.config_type) AS "value"
|
|
570
|
+
* ```
|
|
571
|
+
*/
|
|
572
|
+
export const getConfigValue = new PreparedQuery<IGetConfigValueParams,IGetConfigValueResult>(getConfigValueIR);
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
/** 'UpdateConfigValue' parameters type */
|
|
576
|
+
export interface IUpdateConfigValueParams {
|
|
577
|
+
key: config_type;
|
|
578
|
+
value: string;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/** 'UpdateConfigValue' return type */
|
|
582
|
+
export interface IUpdateConfigValueResult {
|
|
583
|
+
updated: number;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/** 'UpdateConfigValue' query type */
|
|
587
|
+
export interface IUpdateConfigValueQuery {
|
|
588
|
+
params: IUpdateConfigValueParams;
|
|
589
|
+
result: IUpdateConfigValueResult;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
const updateConfigValueIR: any = {"usedParamSet":{"value":true,"key":true},"params":[{"name":"value","required":true,"transform":{"type":"scalar"},"locs":[{"a":31,"b":37}]},{"name":"key","required":true,"transform":{"type":"scalar"},"locs":[{"a":56,"b":60}]}],"statement":"UPDATE pgmb.config\nSET value = :value!::TEXT\nWHERE id = :key!::pgmb.config_type\nRETURNING 1 AS \"updated!\""};
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Query generated from SQL:
|
|
596
|
+
* ```
|
|
597
|
+
* UPDATE pgmb.config
|
|
598
|
+
* SET value = :value!::TEXT
|
|
599
|
+
* WHERE id = :key!::pgmb.config_type
|
|
600
|
+
* RETURNING 1 AS "updated!"
|
|
601
|
+
* ```
|
|
602
|
+
*/
|
|
603
|
+
export const updateConfigValue = new PreparedQuery<IUpdateConfigValueParams,IUpdateConfigValueResult>(updateConfigValueIR);
|
|
604
|
+
|
|
605
|
+
|
|
546
606
|
/** 'MaintainEventsTable' parameters type */
|
|
547
607
|
export type IMaintainEventsTableParams = void;
|
|
548
608
|
|