prostgles-server 4.0.45 → 4.0.46

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.
Files changed (40) hide show
  1. package/dist/DboBuilder/getTablesForSchemaPostgresSQL.d.ts.map +1 -1
  2. package/dist/DboBuilder/getTablesForSchemaPostgresSQL.js +1 -3
  3. package/dist/DboBuilder/getTablesForSchemaPostgresSQL.js.map +1 -1
  4. package/dist/DboBuilder.d.ts.map +1 -1
  5. package/dist/DboBuilder.js.map +1 -1
  6. package/dist/PostgresNotifListenManager.d.ts.map +1 -1
  7. package/dist/PostgresNotifListenManager.js +1 -1
  8. package/dist/PostgresNotifListenManager.js.map +1 -1
  9. package/dist/PubSubManager/PubSubManager.d.ts +2 -1
  10. package/dist/PubSubManager/PubSubManager.d.ts.map +1 -1
  11. package/dist/PubSubManager/PubSubManager.js +86 -84
  12. package/dist/PubSubManager/PubSubManager.js.map +1 -1
  13. package/dist/PubSubManager/getInitQuery.d.ts.map +1 -1
  14. package/dist/PubSubManager/getInitQuery.js +3 -5
  15. package/dist/PubSubManager/getInitQuery.js.map +1 -1
  16. package/dist/PubSubManager/initPubSubManager.d.ts.map +1 -1
  17. package/dist/PubSubManager/initPubSubManager.js +37 -35
  18. package/dist/PubSubManager/initPubSubManager.js.map +1 -1
  19. package/lib/DboBuilder/getTablesForSchemaPostgresSQL.d.ts.map +1 -1
  20. package/lib/DboBuilder/getTablesForSchemaPostgresSQL.js +1 -3
  21. package/lib/DboBuilder/getTablesForSchemaPostgresSQL.ts +1 -3
  22. package/lib/DboBuilder.d.ts.map +1 -1
  23. package/lib/DboBuilder.ts +0 -1
  24. package/lib/PostgresNotifListenManager.d.ts.map +1 -1
  25. package/lib/PostgresNotifListenManager.js +1 -1
  26. package/lib/PostgresNotifListenManager.ts +2 -1
  27. package/lib/PubSubManager/PubSubManager.d.ts +2 -1
  28. package/lib/PubSubManager/PubSubManager.d.ts.map +1 -1
  29. package/lib/PubSubManager/PubSubManager.js +86 -84
  30. package/lib/PubSubManager/PubSubManager.ts +103 -101
  31. package/lib/PubSubManager/getInitQuery.d.ts.map +1 -1
  32. package/lib/PubSubManager/getInitQuery.js +3 -5
  33. package/lib/PubSubManager/getInitQuery.ts +3 -5
  34. package/lib/PubSubManager/initPubSubManager.d.ts.map +1 -1
  35. package/lib/PubSubManager/initPubSubManager.js +37 -35
  36. package/lib/PubSubManager/initPubSubManager.ts +41 -36
  37. package/lib/SchemaWatchManager.ts +1 -1
  38. package/package.json +1 -1
  39. package/tests/client/PID.txt +1 -1
  40. package/tests/server/package-lock.json +1 -1
@@ -185,7 +185,7 @@ export class PubSubManager {
185
185
  schema: "schema_has_changed"
186
186
  }
187
187
  NOTIF_CHANNEL = {
188
- preffix: 'prostgles_',
188
+ preffix: 'prostgles_' as const,
189
189
  getFull: (appID?: string) => {
190
190
  const finalAppId = appID ?? this.appID;
191
191
  if (!finalAppId) throw "No appID";
@@ -253,6 +253,7 @@ export class PubSubManager {
253
253
  }
254
254
 
255
255
  appChecking = false;
256
+ checkedListenerTableCond?: string[];
256
257
  init = initPubSubManager.bind(this);
257
258
 
258
259
 
@@ -269,106 +270,107 @@ export class PubSubManager {
269
270
  try {
270
271
 
271
272
  await this.db.any(`
272
- BEGIN;-- ISOLATION LEVEL SERIALIZABLE;
273
-
274
- /** ${PubSubManager.EXCLUDE_QUERY_FROM_SCHEMA_WATCH_ID}
275
- * Drop stale triggers
276
- * */
277
- DO
278
- $do$
279
- DECLARE trg RECORD;
280
- q TEXT;
281
- ev_trg_needed BOOLEAN := FALSE;
282
- ev_trg_exists BOOLEAN := FALSE;
283
- is_super_user BOOLEAN := FALSE;
284
- BEGIN
285
- --SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
286
-
287
- LOCK TABLE prostgles.app_triggers IN ACCESS EXCLUSIVE MODE;
288
- EXECUTE format(
289
- $q$
290
-
291
- CREATE TEMP TABLE %1$I AS --ON COMMIT DROP AS
292
- SELECT * FROM prostgles.app_triggers;
293
-
294
- DELETE FROM prostgles.app_triggers;
295
-
296
- INSERT INTO prostgles.app_triggers
297
- SELECT * FROM %1$I;
298
-
299
- DROP TABLE IF EXISTS %1$I;
300
- $q$,
301
- ${asValue('triggers_' + this.appID)}
302
- );
303
-
304
- is_super_user := EXISTS (select 1 from pg_user where usename = CURRENT_USER AND usesuper IS TRUE);
305
-
306
- /**
307
- * Delete stale app records
308
- * */
309
- DELETE FROM prostgles.apps
310
- WHERE last_check < NOW() - 8 * check_frequency_ms * interval '1 millisecond';
311
-
312
- DELETE FROM prostgles.app_triggers
313
- WHERE app_id NOT IN (SELECT id FROM prostgles.apps);
314
-
315
- /* DROP the old buggy schema watch trigger */
316
- IF EXISTS (
317
- SELECT 1 FROM pg_catalog.pg_event_trigger
318
- WHERE evtname = 'prostgles_schema_watch_trigger'
319
- ) AND is_super_user IS TRUE
320
- THEN
321
- DROP EVENT TRIGGER IF EXISTS prostgles_schema_watch_trigger;
322
- END IF;
323
-
324
- ev_trg_needed := EXISTS (SELECT 1 FROM prostgles.apps WHERE watching_schema IS TRUE);
325
- ev_trg_exists := EXISTS (
326
- SELECT 1 FROM pg_catalog.pg_event_trigger
327
- WHERE evtname = ${asValue(DB_OBJ_NAMES.schema_watch_trigger)}
328
- );
329
-
330
- -- RAISE NOTICE ' ev_trg_needed %, ev_trg_exists %', ev_trg_needed, ev_trg_exists;
331
-
332
- /**
333
- * DROP stale event trigger
334
- * */
335
- IF is_super_user IS TRUE AND ev_trg_needed IS FALSE AND ev_trg_exists IS TRUE THEN
336
-
337
- SELECT format(
338
- $$ DROP EVENT TRIGGER IF EXISTS %I ; $$
339
- , ${asValue(DB_OBJ_NAMES.schema_watch_trigger)}
340
- )
341
- INTO q;
342
-
343
- --RAISE NOTICE ' DROP EVENT TRIGGER %', q;
344
-
345
- EXECUTE q;
346
-
347
- /**
348
- * CREATE event trigger
349
- * */
350
- ELSIF
351
- is_super_user IS TRUE
352
- AND ev_trg_needed IS TRUE
353
- AND ev_trg_exists IS FALSE
354
- THEN
355
-
356
- DROP EVENT TRIGGER IF EXISTS ${DB_OBJ_NAMES.schema_watch_trigger};
357
- CREATE EVENT TRIGGER ${DB_OBJ_NAMES.schema_watch_trigger} ON ddl_command_end
358
- WHEN TAG IN ('COMMENT', 'CREATE TABLE', 'ALTER TABLE', 'DROP TABLE', 'CREATE VIEW', 'DROP VIEW', 'ALTER VIEW', 'CREATE TABLE AS', 'SELECT INTO')
359
- --WHEN TAG IN ('CREATE TABLE', 'ALTER TABLE', 'DROP TABLE', 'CREATE TRIGGER', 'DROP TRIGGER')
360
- EXECUTE PROCEDURE ${DB_OBJ_NAMES.schema_watch_func}();
361
-
362
- --RAISE NOTICE ' CREATED EVENT TRIGGER %', q;
363
- END IF;
364
-
365
-
366
- END
367
- $do$;
368
-
369
-
370
- COMMIT;
371
- `).catch(e => {
273
+ BEGIN;-- ISOLATION LEVEL SERIALIZABLE;
274
+
275
+ /**
276
+ * ${PubSubManager.EXCLUDE_QUERY_FROM_SCHEMA_WATCH_ID}
277
+ * Drop stale triggers
278
+ * */
279
+ DO
280
+ $do$
281
+ DECLARE trg RECORD;
282
+ q TEXT;
283
+ ev_trg_needed BOOLEAN := FALSE;
284
+ ev_trg_exists BOOLEAN := FALSE;
285
+ is_super_user BOOLEAN := FALSE;
286
+ BEGIN
287
+ --SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
288
+
289
+ LOCK TABLE prostgles.app_triggers IN ACCESS EXCLUSIVE MODE;
290
+ EXECUTE format(
291
+ $q$
292
+
293
+ CREATE TEMP TABLE %1$I AS --ON COMMIT DROP AS
294
+ SELECT * FROM prostgles.app_triggers;
295
+
296
+ DELETE FROM prostgles.app_triggers;
297
+
298
+ INSERT INTO prostgles.app_triggers
299
+ SELECT * FROM %1$I;
300
+
301
+ DROP TABLE IF EXISTS %1$I;
302
+ $q$,
303
+ ${asValue('triggers_' + this.appID)}
304
+ );
305
+
306
+ is_super_user := EXISTS (select 1 from pg_user where usename = CURRENT_USER AND usesuper IS TRUE);
307
+
308
+ /**
309
+ * Delete stale app records, this will delete related triggers
310
+ * */
311
+ DELETE FROM prostgles.apps
312
+ WHERE last_check < NOW() - 8 * check_frequency_ms * interval '1 millisecond';
313
+
314
+ DELETE FROM prostgles.app_triggers
315
+ WHERE app_id NOT IN (SELECT id FROM prostgles.apps);
316
+
317
+ /* DROP the old buggy schema watch trigger */
318
+ IF EXISTS (
319
+ SELECT 1 FROM pg_catalog.pg_event_trigger
320
+ WHERE evtname = 'prostgles_schema_watch_trigger'
321
+ ) AND is_super_user IS TRUE
322
+ THEN
323
+ DROP EVENT TRIGGER IF EXISTS prostgles_schema_watch_trigger;
324
+ END IF;
325
+
326
+ ev_trg_needed := EXISTS (SELECT 1 FROM prostgles.apps WHERE watching_schema IS TRUE);
327
+ ev_trg_exists := EXISTS (
328
+ SELECT 1 FROM pg_catalog.pg_event_trigger
329
+ WHERE evtname = ${asValue(DB_OBJ_NAMES.schema_watch_trigger)}
330
+ );
331
+
332
+ -- RAISE NOTICE ' ev_trg_needed %, ev_trg_exists %', ev_trg_needed, ev_trg_exists;
333
+
334
+ /**
335
+ * DROP stale event trigger
336
+ * */
337
+ IF is_super_user IS TRUE AND ev_trg_needed IS FALSE AND ev_trg_exists IS TRUE THEN
338
+
339
+ SELECT format(
340
+ $$ DROP EVENT TRIGGER IF EXISTS %I ; $$
341
+ , ${asValue(DB_OBJ_NAMES.schema_watch_trigger)}
342
+ )
343
+ INTO q;
344
+
345
+ --RAISE NOTICE ' DROP EVENT TRIGGER %', q;
346
+
347
+ EXECUTE q;
348
+
349
+ /**
350
+ * CREATE event trigger
351
+ * */
352
+ ELSIF
353
+ is_super_user IS TRUE
354
+ AND ev_trg_needed IS TRUE
355
+ AND ev_trg_exists IS FALSE
356
+ THEN
357
+
358
+ DROP EVENT TRIGGER IF EXISTS ${DB_OBJ_NAMES.schema_watch_trigger};
359
+ CREATE EVENT TRIGGER ${DB_OBJ_NAMES.schema_watch_trigger} ON ddl_command_end
360
+ WHEN TAG IN ('COMMENT', 'CREATE TABLE', 'ALTER TABLE', 'DROP TABLE', 'CREATE VIEW', 'DROP VIEW', 'ALTER VIEW', 'CREATE TABLE AS', 'SELECT INTO')
361
+ --WHEN TAG IN ('CREATE TABLE', 'ALTER TABLE', 'DROP TABLE', 'CREATE TRIGGER', 'DROP TRIGGER')
362
+ EXECUTE PROCEDURE ${DB_OBJ_NAMES.schema_watch_func}();
363
+
364
+ --RAISE NOTICE ' CREATED EVENT TRIGGER %', q;
365
+ END IF;
366
+
367
+
368
+ END
369
+ $do$;
370
+
371
+
372
+ COMMIT;
373
+ `).catch(e => {
372
374
  console.error("prepareTriggers failed: ", e);
373
375
  throw e;
374
376
  });
@@ -1 +1 @@
1
- {"version":3,"file":"getInitQuery.d.ts","sourceRoot":"","sources":["getInitQuery.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAG9D,eAAO,MAAM,YAAY;;;;;CAKf,CAAC;AAEX,eAAO,MAAM,YAAY,SAAwB,aAAa,KAAG,QAAQ,MAAM,CA+gB9E,CAAA"}
1
+ {"version":3,"file":"getInitQuery.d.ts","sourceRoot":"","sources":["getInitQuery.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAG9D,eAAO,MAAM,YAAY;;;;;CAKf,CAAC;AAEX,eAAO,MAAM,YAAY,SAAwB,aAAa,KAAG,QAAQ,MAAM,CA6gB9E,CAAA"}
@@ -131,7 +131,6 @@ BEGIN
131
131
  added TIMESTAMP DEFAULT NOW(),
132
132
  application_name TEXT,
133
133
  last_check TIMESTAMP NOT NULL DEFAULT NOW(),
134
- last_check_ended TIMESTAMP NOT NULL DEFAULT NOW(),
135
134
  watching_schema BOOLEAN DEFAULT FALSE,
136
135
  check_frequency_ms INTEGER NOT NULL
137
136
  );
@@ -150,7 +149,7 @@ BEGIN
150
149
 
151
150
  inserted TIMESTAMP NOT NULL DEFAULT NOW(),
152
151
  last_used TIMESTAMP NOT NULL DEFAULT NOW(),
153
- PRIMARY KEY (app_id, table_name, condition) /* This unqique index limits the condition column value to be less than 'SELECT current_setting('block_size'); */
152
+ PRIMARY KEY (app_id, table_name, condition) /* This unique index limits the condition column value to be less than 'SELECT current_setting('block_size'); */
154
153
  );
155
154
  COMMENT ON TABLE prostgles.app_triggers IS 'Tables and conditions that are currently subscribed/synced';
156
155
 
@@ -292,7 +291,6 @@ BEGIN
292
291
  RAISE NOTICE 'trigger dropped due to exception: % % %', err_text, err_detail, err_hint;
293
292
 
294
293
  END IF;
295
-
296
294
 
297
295
  END IF;
298
296
  END IF;
@@ -503,12 +501,12 @@ BEGIN
503
501
  SELECT LEFT(COALESCE(current_query(), ''), 5000)
504
502
  INTO curr_query;
505
503
 
506
- FOR arw IN
504
+ FOR app IN
507
505
  SELECT * FROM prostgles.apps WHERE watching_schema IS TRUE
508
506
 
509
507
  LOOP
510
508
  PERFORM pg_notify(
511
- ${(0, PubSubManager_1.asValue)(this.NOTIF_CHANNEL.preffix)} || arw.id,
509
+ ${(0, PubSubManager_1.asValue)(this.NOTIF_CHANNEL.preffix)} || app.id,
512
510
  concat_ws(
513
511
  ${(0, PubSubManager_1.asValue)(PubSubManager_1.PubSubManager.DELIMITER)},
514
512
  ${(0, PubSubManager_1.asValue)(this.NOTIF_TYPE.schema)}, tg_tag , TG_event, curr_query
@@ -133,7 +133,6 @@ BEGIN
133
133
  added TIMESTAMP DEFAULT NOW(),
134
134
  application_name TEXT,
135
135
  last_check TIMESTAMP NOT NULL DEFAULT NOW(),
136
- last_check_ended TIMESTAMP NOT NULL DEFAULT NOW(),
137
136
  watching_schema BOOLEAN DEFAULT FALSE,
138
137
  check_frequency_ms INTEGER NOT NULL
139
138
  );
@@ -152,7 +151,7 @@ BEGIN
152
151
 
153
152
  inserted TIMESTAMP NOT NULL DEFAULT NOW(),
154
153
  last_used TIMESTAMP NOT NULL DEFAULT NOW(),
155
- PRIMARY KEY (app_id, table_name, condition) /* This unqique index limits the condition column value to be less than 'SELECT current_setting('block_size'); */
154
+ PRIMARY KEY (app_id, table_name, condition) /* This unique index limits the condition column value to be less than 'SELECT current_setting('block_size'); */
156
155
  );
157
156
  COMMENT ON TABLE prostgles.app_triggers IS 'Tables and conditions that are currently subscribed/synced';
158
157
 
@@ -294,7 +293,6 @@ BEGIN
294
293
  RAISE NOTICE 'trigger dropped due to exception: % % %', err_text, err_detail, err_hint;
295
294
 
296
295
  END IF;
297
-
298
296
 
299
297
  END IF;
300
298
  END IF;
@@ -505,12 +503,12 @@ BEGIN
505
503
  SELECT LEFT(COALESCE(current_query(), ''), 5000)
506
504
  INTO curr_query;
507
505
 
508
- FOR arw IN
506
+ FOR app IN
509
507
  SELECT * FROM prostgles.apps WHERE watching_schema IS TRUE
510
508
 
511
509
  LOOP
512
510
  PERFORM pg_notify(
513
- ${asValue(this.NOTIF_CHANNEL.preffix)} || arw.id,
511
+ ${asValue(this.NOTIF_CHANNEL.preffix)} || app.id,
514
512
  concat_ws(
515
513
  ${asValue(PubSubManager.DELIMITER)},
516
514
  ${asValue(this.NOTIF_TYPE.schema)}, tg_tag , TG_event, curr_query
@@ -1 +1 @@
1
- {"version":3,"file":"initPubSubManager.d.ts","sourceRoot":"","sources":["initPubSubManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAI9D,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CAwH/F"}
1
+ {"version":3,"file":"initPubSubManager.d.ts","sourceRoot":"","sources":["initPubSubManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAgB,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAI9D,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,aAAa,GAAG,SAAS,CAAC,CA6H/F"}
@@ -19,11 +19,42 @@ async function initPubSubManager() {
19
19
  this.appID = raw.id;
20
20
  if (!this.appCheck) {
21
21
  this.appCheck = setInterval(async () => {
22
- let appQ = "";
22
+ let checkForStaleTriggers = "";
23
23
  try { // drop owned by api
24
24
  this.appChecking = true;
25
25
  const listeners = this.getActiveListeners();
26
- appQ = `
26
+ const checkedListenerTableCond = listeners.map(l => `${l.table_name}.${l.condition}`);
27
+ let dataTriggerCheckQuery = "";
28
+ if (this.checkedListenerTableCond?.sort().join() !== checkedListenerTableCond.sort().join()) {
29
+ this.checkedListenerTableCond = checkedListenerTableCond;
30
+ dataTriggerCheckQuery = `
31
+ /* Delete unused triggers. Might deadlock */
32
+ IF EXISTS ( SELECT 1 FROM prostgles.app_triggers)
33
+
34
+ THEN
35
+
36
+ /* TODO: Fixed deadlocks */
37
+ --LOCK TABLE prostgles.app_triggers IN ACCESS EXCLUSIVE MODE;
38
+
39
+ /* UPDATE currently used triggers */
40
+ ${!listeners.length ? "" : `
41
+ UPDATE prostgles.app_triggers
42
+ SET last_used = CASE WHEN (table_name, condition) IN (
43
+ ${listeners.map(l => ` ( ${(0, PubSubManager_1.asValue)(l.table_name)}, ${(0, PubSubManager_1.asValue)(l.condition)} ) `).join(", ")}
44
+ ) THEN NOW() ELSE last_used END
45
+ WHERE app_id = ${(0, PubSubManager_1.asValue)(this.appID)};
46
+ `}
47
+
48
+ /* DELETE stale triggers for current app. Other triggers will be deleted on app startup */
49
+ DELETE FROM prostgles.app_triggers
50
+ WHERE app_id = ${(0, PubSubManager_1.asValue)(this.appID)}
51
+ AND last_used < NOW() - 4 * ${(0, PubSubManager_1.asValue)(this.appCheckFrequencyMS)} * interval '1 millisecond'; -- 10 seconds at the moment
52
+
53
+ END IF;
54
+
55
+ `;
56
+ }
57
+ checkForStaleTriggers = `
27
58
  DO $$
28
59
  BEGIN
29
60
 
@@ -41,46 +72,17 @@ async function initPubSubManager() {
41
72
  )
42
73
  THEN
43
74
 
75
+ /* Last check used to remove disconnected apps */
44
76
  UPDATE prostgles.apps
45
77
  SET last_check = NOW()
46
78
  WHERE id = ${(0, PubSubManager_1.asValue)(this.appID)};
47
79
 
48
-
49
-
50
- /* Delete unused triggers. Might deadlock */
51
- IF EXISTS ( SELECT 1 FROM prostgles.app_triggers)
52
-
53
- THEN
54
-
55
- /* TODO: Fixed deadlocks */
56
- --LOCK TABLE prostgles.app_triggers IN ACCESS EXCLUSIVE MODE;
57
-
58
- /* UPDATE currently used triggers */
59
- ${!listeners.length ? "" : `
60
- UPDATE prostgles.app_triggers
61
- SET last_used = CASE WHEN (table_name, condition) IN (
62
- ${listeners.map(l => ` ( ${(0, PubSubManager_1.asValue)(l.table_name)}, ${(0, PubSubManager_1.asValue)(l.condition)} ) `).join(", ")}
63
- ) THEN NOW() ELSE last_used END
64
- WHERE app_id = ${(0, PubSubManager_1.asValue)(this.appID)};
65
- `}
66
-
67
- /* DELETE stale triggers for current app. Other triggers will be deleted on app startup */
68
- DELETE FROM prostgles.app_triggers
69
- WHERE app_id = ${(0, PubSubManager_1.asValue)(this.appID)}
70
- AND last_used < NOW() - 4 * ${(0, PubSubManager_1.asValue)(this.appCheckFrequencyMS)} * interval '1 millisecond'; -- 10 seconds at the moment
71
-
72
- END IF;
73
-
74
- UPDATE prostgles.apps
75
- SET last_check_ended = NOW()
76
- WHERE id = ${(0, PubSubManager_1.asValue)(this.appID)};
77
-
78
-
80
+ ${dataTriggerCheckQuery}
79
81
  END IF;
80
82
 
81
83
  END $$;
82
84
  `;
83
- await this.db.any(appQ);
85
+ await this.db.any(checkForStaleTriggers);
84
86
  tries = 5;
85
87
  (0, PubSubManager_1.log)("updated last_check");
86
88
  }
@@ -97,7 +99,7 @@ async function initPubSubManager() {
97
99
  if (tries <= 0 || e?.code === "3D000") { // && e.message.includes(this.db.$cn.database)
98
100
  clearInterval(this.appCheck);
99
101
  }
100
- console.error("appCheck FAILED: \n", e, appQ);
102
+ console.error("appCheck FAILED: \n", e, checkForStaleTriggers);
101
103
  }
102
104
  this.appChecking = false;
103
105
  }, 0.8 * this.appCheckFrequencyMS);
@@ -24,14 +24,45 @@ export async function initPubSubManager(this: PubSubManager): Promise<PubSubMana
24
24
  if (!this.appCheck) {
25
25
 
26
26
  this.appCheck = setInterval(async () => {
27
- let appQ = "";
27
+ let checkForStaleTriggers = "";
28
28
  try { // drop owned by api
29
29
 
30
30
  this.appChecking = true;
31
31
 
32
32
  const listeners = this.getActiveListeners();
33
+ const checkedListenerTableCond = listeners.map(l => `${l.table_name}.${l.condition}`);
34
+ let dataTriggerCheckQuery = "";
35
+ if(this.checkedListenerTableCond?.sort().join() !== checkedListenerTableCond.sort().join()){
36
+ this.checkedListenerTableCond = checkedListenerTableCond;
37
+ dataTriggerCheckQuery = `
38
+ /* Delete unused triggers. Might deadlock */
39
+ IF EXISTS ( SELECT 1 FROM prostgles.app_triggers)
40
+
41
+ THEN
42
+
43
+ /* TODO: Fixed deadlocks */
44
+ --LOCK TABLE prostgles.app_triggers IN ACCESS EXCLUSIVE MODE;
45
+
46
+ /* UPDATE currently used triggers */
47
+ ${!listeners.length? "" : `
48
+ UPDATE prostgles.app_triggers
49
+ SET last_used = CASE WHEN (table_name, condition) IN (
50
+ ${listeners.map(l => ` ( ${asValue(l.table_name)}, ${asValue(l.condition)} ) `).join(", ")}
51
+ ) THEN NOW() ELSE last_used END
52
+ WHERE app_id = ${asValue(this.appID)};
53
+ `}
54
+
55
+ /* DELETE stale triggers for current app. Other triggers will be deleted on app startup */
56
+ DELETE FROM prostgles.app_triggers
57
+ WHERE app_id = ${asValue(this.appID)}
58
+ AND last_used < NOW() - 4 * ${asValue(this.appCheckFrequencyMS)} * interval '1 millisecond'; -- 10 seconds at the moment
59
+
60
+ END IF;
61
+
62
+ `
63
+ }
33
64
 
34
- appQ = `
65
+ checkForStaleTriggers = `
35
66
  DO $$
36
67
  BEGIN
37
68
 
@@ -49,53 +80,27 @@ export async function initPubSubManager(this: PubSubManager): Promise<PubSubMana
49
80
  )
50
81
  THEN
51
82
 
83
+ /* Last check used to remove disconnected apps */
52
84
  UPDATE prostgles.apps
53
85
  SET last_check = NOW()
54
86
  WHERE id = ${asValue(this.appID)};
55
87
 
56
-
57
-
58
- /* Delete unused triggers. Might deadlock */
59
- IF EXISTS ( SELECT 1 FROM prostgles.app_triggers)
60
-
61
- THEN
62
-
63
- /* TODO: Fixed deadlocks */
64
- --LOCK TABLE prostgles.app_triggers IN ACCESS EXCLUSIVE MODE;
65
-
66
- /* UPDATE currently used triggers */
67
- ${!listeners.length? "" : `
68
- UPDATE prostgles.app_triggers
69
- SET last_used = CASE WHEN (table_name, condition) IN (
70
- ${listeners.map(l => ` ( ${asValue(l.table_name)}, ${asValue(l.condition)} ) `).join(", ")}
71
- ) THEN NOW() ELSE last_used END
72
- WHERE app_id = ${asValue(this.appID)};
73
- `}
74
-
75
- /* DELETE stale triggers for current app. Other triggers will be deleted on app startup */
76
- DELETE FROM prostgles.app_triggers
77
- WHERE app_id = ${asValue(this.appID)}
78
- AND last_used < NOW() - 4 * ${asValue(this.appCheckFrequencyMS)} * interval '1 millisecond'; -- 10 seconds at the moment
79
-
80
- END IF;
81
-
82
- UPDATE prostgles.apps
83
- SET last_check_ended = NOW()
84
- WHERE id = ${asValue(this.appID)};
85
-
86
-
88
+ ${dataTriggerCheckQuery}
87
89
  END IF;
88
90
 
89
91
  END $$;
90
92
  `
91
- await this.db.any(appQ);
93
+ await this.db.any(checkForStaleTriggers);
92
94
  tries = 5;
93
95
  log("updated last_check");
94
96
  } catch (e: any) {
95
97
  tries --;
96
98
 
97
99
  /** In some cases a query idles and blocks everything else. Terminate all similar queries */
98
- this.db.any("SELECT state, pg_terminate_backend(pid) from pg_stat_activity WHERE query ilike ${qid} and pid <> pg_backend_pid();", { qid: "%" + REALTIME_TRIGGER_CHECK_QUERY + "%" });
100
+ this.db.any(
101
+ "SELECT state, pg_terminate_backend(pid) from pg_stat_activity WHERE query ilike ${qid} and pid <> pg_backend_pid();",
102
+ { qid: "%" + REALTIME_TRIGGER_CHECK_QUERY + "%" }
103
+ );
99
104
 
100
105
  /** If no tries left
101
106
  * OR
@@ -106,7 +111,7 @@ export async function initPubSubManager(this: PubSubManager): Promise<PubSubMana
106
111
  if(tries <= 0 || e?.code === "3D000"){ // && e.message.includes(this.db.$cn.database)
107
112
  clearInterval(this.appCheck);
108
113
  }
109
- console.error("appCheck FAILED: \n", e, appQ);
114
+ console.error("appCheck FAILED: \n", e, checkForStaleTriggers);
110
115
  }
111
116
 
112
117
  this.appChecking = false;
@@ -32,7 +32,7 @@ export class SchemaWatchManager {
32
32
  const dbuilder = await DboBuilder.create(this as any);
33
33
  if(dbuilder.tsTypesDefinition !== this.prostgles.dboBuilder.tsTypesDefinition){
34
34
  this.prostgles.refreshDBO();
35
- this.prostgles.init(this.prostgles.opts.onReady);
35
+ this.prostgles.init(this.prostgles.opts.onReady, "schema-watch-interval");
36
36
  }
37
37
  }, prgl.opts.watchSchemaType.checkIntervalMillis)
38
38
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prostgles-server",
3
- "version": "4.0.45",
3
+ "version": "4.0.46",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1 +1 @@
1
- 14341
1
+ 136733
@@ -21,7 +21,7 @@
21
21
  },
22
22
  "../..": {
23
23
  "name": "prostgles-server",
24
- "version": "4.0.44",
24
+ "version": "4.0.45",
25
25
  "license": "MIT",
26
26
  "dependencies": {
27
27
  "@aws-sdk/client-s3": "^3.272.0",