prostgles-server 4.2.79 → 4.2.81

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.
@@ -1,17 +1,47 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.initPubSubManager = exports.REALTIME_TRIGGER_CHECK_QUERY = void 0;
3
+ exports.initPubSubManager = exports.tout = exports.REALTIME_TRIGGER_CHECK_QUERY = void 0;
4
+ const prostgles_types_1 = require("prostgles-types");
4
5
  const PostgresNotifListenManager_1 = require("../PostgresNotifListenManager");
5
6
  const getWatchSchemaTagList_1 = require("../SchemaWatch/getWatchSchemaTagList");
6
7
  const PubSubManager_1 = require("./PubSubManager");
7
- const getInitQuery_1 = require("./getInitQuery");
8
+ const getPubSubManagerInitQuery_1 = require("./getPubSubManagerInitQuery");
8
9
  exports.REALTIME_TRIGGER_CHECK_QUERY = "prostgles-server internal query used to manage realtime triggers";
10
+ const tout = (ms) => new Promise(res => setTimeout(res, ms));
11
+ exports.tout = tout;
9
12
  async function initPubSubManager() {
10
13
  if (!this.getIsDestroyed())
11
14
  return undefined;
12
15
  try {
13
- const initQuery = await getInitQuery_1.getInitQuery.bind(this)();
14
- await this.db.any(initQuery);
16
+ const initQuery = await getPubSubManagerInitQuery_1.getPubSubManagerInitQuery.bind(this)();
17
+ /**
18
+ * High database activity might cause deadlocks.
19
+ * Must retry
20
+ */
21
+ let didDeadlock = false;
22
+ let tries = 3;
23
+ let error;
24
+ while ((0, prostgles_types_1.isDefined)(initQuery) && tries > 0) {
25
+ try {
26
+ /** Try to reduce race condition deadlocks due to multiple clients connecting at the same time */
27
+ await (0, exports.tout)(Math.random());
28
+ await this.db.any(initQuery);
29
+ error = undefined;
30
+ tries = 0;
31
+ }
32
+ catch (e) {
33
+ if (!didDeadlock && (0, prostgles_types_1.isObject)(e) && e.code === "40P01") {
34
+ didDeadlock = true;
35
+ tries = 5;
36
+ console.error("Deadlock detected. Retrying...");
37
+ }
38
+ error = e;
39
+ tries--;
40
+ }
41
+ }
42
+ if (error) {
43
+ throw error;
44
+ }
15
45
  if (!this.getIsDestroyed())
16
46
  return;
17
47
  /* Prepare App id */
@@ -1 +1 @@
1
- {"version":3,"file":"initPubSubManager.js","sourceRoot":"","sources":["../../lib/PubSubManager/initPubSubManager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"initPubSubManager.js","sourceRoot":"","sources":["../../lib/PubSubManager/initPubSubManager.ts"],"names":[],"mappings":"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"}
@@ -22,7 +22,7 @@ import { EventTypes } from "../Logging";
22
22
  import { TableRule } from "../PublishParser/PublishParser";
23
23
  import { syncData } from "../SyncReplication";
24
24
  import { addSub } from "./addSub";
25
- import { DB_OBJ_NAMES } from "./getInitQuery";
25
+ import { DB_OBJ_NAMES } from "./getPubSubManagerInitQuery";
26
26
  import { notifListener } from "./notifListener";
27
27
  import { pushSubData } from "./pushSubData";
28
28
 
@@ -1,4 +1,6 @@
1
1
 
2
+ import { tryCatch } from "prostgles-types";
3
+ import { pgp } from "../DboBuilder/DboBuilderTypes";
2
4
  import { asValue, NOTIF_CHANNEL, NOTIF_TYPE, PubSubManager } from "./PubSubManager";
3
5
  const { version } = require("../../package.json");
4
6
  import { getAppCheckQuery } from "./orphanTriggerCheck";
@@ -10,14 +12,23 @@ export const DB_OBJ_NAMES = {
10
12
  schema_watch_trigger: "prostgles_schema_watch_trigger_new"
11
13
  } as const;
12
14
 
13
- export const getInitQuery = async function(this: PubSubManager): Promise<string> {
14
-
15
- const getQuery = async (withoutHash = false): Promise<string> => {
16
- const { schema_md5 = "none" } = withoutHash? {} : await this.db.oneOrNone("SELECT md5($1) as schema_md5", [await getQuery(true)]);
17
-
18
- return `
19
-
20
- BEGIN; -- ISOLATION LEVEL SERIALIZABLE;-- TRANSACTION ISOLATION LEVEL SERIALIZABLE;
15
+ const PROSTGLES_SCHEMA_EXISTS_QUERY = `
16
+ SELECT 1
17
+ FROM information_schema.columns
18
+ WHERE table_schema = 'prostgles'
19
+ AND table_name = 'versions'
20
+ AND column_name = 'schema_md5'
21
+ `;
22
+ const PROSTGLES_SCHEMA_VERSION_OK_QUERY = `
23
+ SELECT 1
24
+ FROM prostgles.versions
25
+ WHERE (string_to_array(version, '.')::int[] > string_to_array(\${version}, '.')::int[])
26
+ OR (string_to_array(version, '.')::int[] = string_to_array(\${version}, '.')::int[])
27
+ AND schema_md5 = \${schema_md5}
28
+ `;
29
+
30
+ const getInitQuery = (debugMode: boolean | undefined) => `
31
+ BEGIN; -- TRANSACTION ISOLATION LEVEL SERIALIZABLE;
21
32
 
22
33
  --SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
23
34
 
@@ -29,9 +40,6 @@ DO
29
40
  $do$
30
41
  BEGIN
31
42
 
32
- /* Reduce deadlocks */
33
- PERFORM pg_sleep(random());
34
-
35
43
  /* Drop older version. */
36
44
  IF EXISTS (SELECT 1 FROM information_schema.schemata WHERE schema_name = 'prostgles') THEN
37
45
 
@@ -39,23 +47,14 @@ BEGIN
39
47
  IF
40
48
  /* Backwards compatibility. Cannot check schema version */
41
49
  NOT EXISTS(
42
- SELECT 1
43
- FROM information_schema.columns
44
- WHERE table_schema = 'prostgles'
45
- AND table_name = 'versions'
46
- AND column_name = 'schema_md5'
50
+ ${PROSTGLES_SCHEMA_EXISTS_QUERY}
47
51
  )
48
52
  THEN
49
53
  DROP SCHEMA IF EXISTS prostgles CASCADE;
50
54
  ELSIF
51
55
  /* There is no newer version or same same version but different schema */
52
56
  NOT EXISTS (
53
- SELECT 1
54
- FROM prostgles.versions
55
- WHERE
56
- (string_to_array(version, '.')::int[] > string_to_array(${asValue(version)}, '.')::int[])
57
- OR (string_to_array(version, '.')::int[] = string_to_array(${asValue(version)}, '.')::int[])
58
- AND schema_md5 = ${asValue(schema_md5)}
57
+ ${PROSTGLES_SCHEMA_VERSION_OK_QUERY}
59
58
  )
60
59
  THEN
61
60
  DROP SCHEMA IF EXISTS prostgles CASCADE;
@@ -83,7 +82,7 @@ BEGIN
83
82
  COMMENT ON TABLE prostgles.versions IS 'Stores the prostgles schema creation query hash and package version number to identify when a newer schema needs to be re-created';
84
83
 
85
84
  INSERT INTO prostgles.versions(version, schema_md5)
86
- VALUES(${asValue(version)}, ${asValue(schema_md5)})
85
+ VALUES(${asValue(version)}, \${schema_md5})
87
86
  ON CONFLICT DO NOTHING;
88
87
 
89
88
 
@@ -307,7 +306,7 @@ BEGIN
307
306
  THEN concat_ws('; ', 'error', err_text, err_detail, err_hint, 'query: ' || query )
308
307
  ELSE COALESCE(v_trigger.cids, '')
309
308
  END
310
- ${this.dboBuilder.prostgles.opts.DEBUG_MODE? (", COALESCE(current_query(), 'current_query ??'), ' ', query") : ""}
309
+ ${debugMode? (", COALESCE(current_query(), 'current_query ??'), ' ', query") : ""}
311
310
  ), 7999/4) -- Some chars are 2bytes -> 'Ω'
312
311
  );
313
312
  END LOOP;
@@ -506,7 +505,7 @@ BEGIN
506
505
  json_build_object(
507
506
  'TG_OP', TG_OP,
508
507
  'duration', (EXTRACT(EPOCH FROM now()) * 1000) - start_time,
509
- 'query', ${this.dboBuilder.prostgles.opts.DEBUG_MODE? 'LEFT(current_query(), 400)' : "'Only shown in debug mode'"}
508
+ 'query', ${debugMode? 'LEFT(current_query(), 400)' : "'Only shown in debug mode'"}
510
509
  )
511
510
  )::TEXT, 7999/4)
512
511
  );
@@ -568,7 +567,7 @@ BEGIN
568
567
  ${asValue(NOTIF_TYPE.schema)},
569
568
  tg_tag ,
570
569
  TG_event,
571
- ${this.dboBuilder.prostgles.opts.DEBUG_MODE? 'curr_query' : "'Only shown in debug mode'"}
570
+ ${debugMode? 'curr_query' : "'Only shown in debug mode'"}
572
571
  ), 7999/4)
573
572
  );
574
573
  END LOOP;
@@ -589,11 +588,31 @@ BEGIN
589
588
  END
590
589
  $do$;
591
590
 
592
-
593
591
  COMMIT;
594
- `};
595
-
596
- const res = getQuery();
592
+ `
593
+
594
+ /**
595
+ * Initialize the prostgles schema and functions needed for realtime data and schema changes
596
+ * undefined returned if the database contains the apropriate prostgles schema
597
+ */
598
+ export const getPubSubManagerInitQuery = async function(this: PubSubManager): Promise<string | undefined> {
599
+
600
+ const initQuery = getInitQuery(this.dboBuilder.prostgles.opts.DEBUG_MODE);
601
+ const { schema_md5 = "none" } = await this.db.oneOrNone("SELECT md5($1) as schema_md5", [initQuery.trim()]);
602
+ const query = pgp.as.format(initQuery, { schema_md5, version });
603
+ const existingSchema = await this.db.any(PROSTGLES_SCHEMA_EXISTS_QUERY);
604
+ if(!existingSchema.length){
605
+ return query;
606
+ }
607
+ const { existingSchemaVersions } = await tryCatch(async () => {
608
+ const existingSchemaVersions = await this.db.any(PROSTGLES_SCHEMA_VERSION_OK_QUERY, { schema_md5, version });
609
+ return {
610
+ existingSchemaVersions
611
+ }
612
+ });
613
+ if(!existingSchemaVersions?.length){
614
+ return query;
615
+ }
597
616
 
598
- return res;
617
+ return undefined;
599
618
  }
@@ -1,16 +1,48 @@
1
+ import { isDefined, isObject } from "prostgles-types";
1
2
  import { PostgresNotifListenManager } from "../PostgresNotifListenManager";
2
3
  import { getWatchSchemaTagList } from "../SchemaWatch/getWatchSchemaTagList";
3
4
  import { NOTIF_CHANNEL, PubSubManager, asValue } from "./PubSubManager";
4
- import { getInitQuery } from "./getInitQuery";
5
+ import { getPubSubManagerInitQuery } from "./getPubSubManagerInitQuery";
5
6
  export const REALTIME_TRIGGER_CHECK_QUERY = "prostgles-server internal query used to manage realtime triggers" as const;
6
7
 
8
+ export const tout = (ms: number) => new Promise(res => setTimeout(res, ms));
9
+
7
10
  export async function initPubSubManager(this: PubSubManager): Promise<PubSubManager | undefined> {
8
11
  if (!this.getIsDestroyed()) return undefined;
9
12
 
10
13
  try {
11
14
 
12
- const initQuery = await getInitQuery.bind(this)()
13
- await this.db.any(initQuery);
15
+ const initQuery = await getPubSubManagerInitQuery.bind(this)();
16
+
17
+ /**
18
+ * High database activity might cause deadlocks.
19
+ * Must retry
20
+ */
21
+ let didDeadlock = false;
22
+ let tries = 3;
23
+ let error: any;
24
+ while (isDefined(initQuery) && tries > 0) {
25
+ try {
26
+ /** Try to reduce race condition deadlocks due to multiple clients connecting at the same time */
27
+ await tout(Math.random());
28
+
29
+ await this.db.any(initQuery);
30
+ error = undefined;
31
+ tries = 0;
32
+ } catch (e: any) {
33
+ if(!didDeadlock && isObject(e) && e.code === "40P01"){
34
+ didDeadlock = true;
35
+ tries = 5;
36
+ console.error("Deadlock detected. Retrying...");
37
+ }
38
+ error = e;
39
+ tries --;
40
+ }
41
+ }
42
+ if(error){
43
+ throw error;
44
+ }
45
+
14
46
  if (!this.getIsDestroyed()) return;
15
47
 
16
48
  /* Prepare App id */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prostgles-server",
3
- "version": "4.2.79",
3
+ "version": "4.2.81",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -40,8 +40,8 @@
40
40
  "check-disk-space": "^3.4.0",
41
41
  "file-type": "^18.5.0",
42
42
  "pg": "^8.11.5",
43
- "pg-cursor": "^2.10.5",
44
- "pg-promise": "^11.6.0",
43
+ "pg-cursor": "^2.11.0",
44
+ "pg-promise": "^11.8.0",
45
45
  "prostgles-client": "^4.0.53",
46
46
  "prostgles-types": "^4.0.87"
47
47
  },
@@ -121,14 +121,14 @@
121
121
  }
122
122
  },
123
123
  "node_modules/engine.io-client": {
124
- "version": "6.5.3",
125
- "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz",
126
- "integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==",
124
+ "version": "6.5.4",
125
+ "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.4.tgz",
126
+ "integrity": "sha512-GeZeeRjpD2qf49cZQ0Wvh/8NJNfeXkXXcoGh+F77oEAgo9gUHwT1fCRxSNU+YEEaysOJTnsFHmM5oAcPy4ntvQ==",
127
127
  "dependencies": {
128
128
  "@socket.io/component-emitter": "~3.1.0",
129
129
  "debug": "~4.3.1",
130
130
  "engine.io-parser": "~5.2.1",
131
- "ws": "~8.11.0",
131
+ "ws": "~8.17.1",
132
132
  "xmlhttprequest-ssl": "~2.0.0"
133
133
  }
134
134
  },
@@ -268,27 +268,6 @@
268
268
  }
269
269
  }
270
270
  },
271
- "node_modules/jsdom/node_modules/ws": {
272
- "version": "8.16.0",
273
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz",
274
- "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==",
275
- "dev": true,
276
- "engines": {
277
- "node": ">=10.0.0"
278
- },
279
- "peerDependencies": {
280
- "bufferutil": "^4.0.1",
281
- "utf-8-validate": ">=5.0.2"
282
- },
283
- "peerDependenciesMeta": {
284
- "bufferutil": {
285
- "optional": true
286
- },
287
- "utf-8-validate": {
288
- "optional": true
289
- }
290
- }
291
- },
292
271
  "node_modules/json-schema": {
293
272
  "version": "0.4.0",
294
273
  "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz",
@@ -615,15 +594,15 @@
615
594
  }
616
595
  },
617
596
  "node_modules/ws": {
618
- "version": "8.11.0",
619
- "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz",
620
- "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==",
597
+ "version": "8.17.1",
598
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
599
+ "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
621
600
  "engines": {
622
601
  "node": ">=10.0.0"
623
602
  },
624
603
  "peerDependencies": {
625
604
  "bufferutil": "^4.0.1",
626
- "utf-8-validate": "^5.0.2"
605
+ "utf-8-validate": ">=5.0.2"
627
606
  },
628
607
  "peerDependenciesMeta": {
629
608
  "bufferutil": {
@@ -8,6 +8,33 @@ import { describe, test } from "node:test";
8
8
  export const clientOnlyQueries = async (db: DBHandlerClient, auth: Auth, log: (...args: any[]) => any, methods, tableSchema: DBSchemaTable[], token: string) => {
9
9
 
10
10
  await describe("Client only queries", async (t) => {
11
+
12
+ await test("SQL Stream more than 1k records", async ( ) => {
13
+ const expectedRowCount = 2e3;
14
+ await tryRunP("", async (resolve, reject) => {
15
+ let rows: any[] = [];
16
+ const res = await db.sql!(`SELECT * FROM generate_series(1, ${expectedRowCount})`, {}, { returnType: "stream" });
17
+ const listener = async (packet: SocketSQLStreamPacket) => {
18
+ if(packet.type === "error"){
19
+ reject(packet.error);
20
+ } else {
21
+ if(packet.rows){
22
+ rows = [
23
+ ...rows,
24
+ ...packet.rows
25
+ ]
26
+ }
27
+ if(packet.ended){
28
+ assert.equal(packet.ended, true);
29
+ assert.equal(rows.length, expectedRowCount);
30
+ resolve("ok");
31
+ }
32
+ }
33
+ };
34
+ await res.start(listener);
35
+ });
36
+ });
37
+
11
38
  await test("SQL Stream persistedConnection with streamLimit works for subsequent queries", async () => {
12
39
  await tryRunP("", async (resolve, reject) => {
13
40
  const query = "SELECT * FROM generate_series(1, 100)";