pg-cache 1.6.7 → 1.6.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.
Files changed (3) hide show
  1. package/esm/pg.js +54 -0
  2. package/package.json +3 -3
  3. package/pg.js +54 -0
package/esm/pg.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import pg from 'pg';
2
2
  import { getPgEnvOptions } from 'pg-env';
3
+ import { Logger } from '@pgpmjs/logger';
3
4
  import { pgCache } from './lru';
5
+ const log = new Logger('pg-cache');
4
6
  const getDbString = (user, password, host, port, database) => `postgres://${user}:${password}@${host}:${port}/${database}`;
5
7
  export const getPgPool = (pgConfig) => {
6
8
  const config = getPgEnvOptions(pgConfig);
@@ -12,6 +14,58 @@ export const getPgPool = (pgConfig) => {
12
14
  }
13
15
  const connectionString = getDbString(user, password, host, port, database);
14
16
  const pgPool = new pg.Pool({ connectionString });
17
+ /**
18
+ * IMPORTANT: Pool-level error handler for idle connection errors.
19
+ *
20
+ * WHY THIS EXISTS:
21
+ * pg-pool maintains a pool of database connections. When a connection is idle
22
+ * (not actively running a query) and the server terminates it (e.g., during
23
+ * database cleanup via pg_terminate_backend), pg-pool emits an 'error' event
24
+ * on the pool's EventEmitter. In Node.js, an EventEmitter 'error' event with
25
+ * no listeners is FATAL and crashes the entire process with an unhelpful
26
+ * stack trace showing internal pg-pool/pg-protocol objects.
27
+ *
28
+ * WHY THIS IS SAFE (does NOT swallow real errors):
29
+ * This handler ONLY catches errors emitted on IDLE pooled connections via
30
+ * the EventEmitter pattern. It does NOT intercept errors from active queries.
31
+ *
32
+ * Error paths in pg-pool:
33
+ * 1. QUERY ERRORS (pool.query(), client.query()):
34
+ * - Returned via Promise rejection
35
+ * - Bubble up through async/await as normal exceptions
36
+ * - NOT affected by this handler - they still throw as expected
37
+ * - Examples: syntax errors, constraint violations, connection refused
38
+ *
39
+ * 2. IDLE CONNECTION ERRORS (this handler):
40
+ * - Emitted via EventEmitter when server kills an idle connection
41
+ * - Without a handler: crashes Node.js process
42
+ * - With this handler: logged and process continues
43
+ * - Examples: pg_terminate_backend during cleanup, server restart
44
+ *
45
+ * WHEN THIS FIRES:
46
+ * - pgpm test-packages creates temp databases, deploys, then drops them
47
+ * - Dropping requires pg_terminate_backend() to kill active connections
48
+ * - Idle connections in the pool receive PostgreSQL error 57P01
49
+ * - This handler catches that expected cleanup error
50
+ *
51
+ * PostgreSQL error codes handled:
52
+ * - 57P01: admin_shutdown (terminating connection due to administrator command)
53
+ * This is EXPECTED during database teardown and logged at debug level.
54
+ *
55
+ * All other error codes are logged at error level for visibility but do not
56
+ * crash the process, allowing the test harness to continue and report results.
57
+ */
58
+ pgPool.on('error', (err) => {
59
+ if (err.code === '57P01') {
60
+ // Expected during database cleanup - log at debug level
61
+ log.debug(`Pool ${database} connection terminated (expected during cleanup): ${err.message}`);
62
+ }
63
+ else {
64
+ // Unexpected pool error - log at error level for visibility
65
+ // Note: This does NOT swallow query errors - those still throw via Promise rejection
66
+ log.error(`Pool ${database} unexpected idle connection error [${err.code || 'unknown'}]: ${err.message}`);
67
+ }
68
+ });
15
69
  pgCache.set(database, pgPool);
16
70
  return pgPool;
17
71
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pg-cache",
3
- "version": "1.6.7",
3
+ "version": "1.6.9",
4
4
  "author": "Constructive <developers@constructive.io>",
5
5
  "description": "PostgreSQL connection pool LRU cache manager",
6
6
  "main": "index.js",
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "dependencies": {
32
32
  "@pgpmjs/logger": "^1.3.5",
33
- "@pgpmjs/types": "^2.12.5",
33
+ "@pgpmjs/types": "^2.12.6",
34
34
  "lru-cache": "^11.2.4",
35
35
  "pg": "^8.16.3",
36
36
  "pg-env": "^1.2.4"
@@ -48,5 +48,5 @@
48
48
  "connection",
49
49
  "constructive"
50
50
  ],
51
- "gitHead": "e45ec95404e48d0c0542da882a3baea0cd6de1c7"
51
+ "gitHead": "fc182ff9e4c4745a3e86eda6d58e3b0061f36564"
52
52
  }
package/pg.js CHANGED
@@ -6,7 +6,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getPgPool = void 0;
7
7
  const pg_1 = __importDefault(require("pg"));
8
8
  const pg_env_1 = require("pg-env");
9
+ const logger_1 = require("@pgpmjs/logger");
9
10
  const lru_1 = require("./lru");
11
+ const log = new logger_1.Logger('pg-cache');
10
12
  const getDbString = (user, password, host, port, database) => `postgres://${user}:${password}@${host}:${port}/${database}`;
11
13
  const getPgPool = (pgConfig) => {
12
14
  const config = (0, pg_env_1.getPgEnvOptions)(pgConfig);
@@ -18,6 +20,58 @@ const getPgPool = (pgConfig) => {
18
20
  }
19
21
  const connectionString = getDbString(user, password, host, port, database);
20
22
  const pgPool = new pg_1.default.Pool({ connectionString });
23
+ /**
24
+ * IMPORTANT: Pool-level error handler for idle connection errors.
25
+ *
26
+ * WHY THIS EXISTS:
27
+ * pg-pool maintains a pool of database connections. When a connection is idle
28
+ * (not actively running a query) and the server terminates it (e.g., during
29
+ * database cleanup via pg_terminate_backend), pg-pool emits an 'error' event
30
+ * on the pool's EventEmitter. In Node.js, an EventEmitter 'error' event with
31
+ * no listeners is FATAL and crashes the entire process with an unhelpful
32
+ * stack trace showing internal pg-pool/pg-protocol objects.
33
+ *
34
+ * WHY THIS IS SAFE (does NOT swallow real errors):
35
+ * This handler ONLY catches errors emitted on IDLE pooled connections via
36
+ * the EventEmitter pattern. It does NOT intercept errors from active queries.
37
+ *
38
+ * Error paths in pg-pool:
39
+ * 1. QUERY ERRORS (pool.query(), client.query()):
40
+ * - Returned via Promise rejection
41
+ * - Bubble up through async/await as normal exceptions
42
+ * - NOT affected by this handler - they still throw as expected
43
+ * - Examples: syntax errors, constraint violations, connection refused
44
+ *
45
+ * 2. IDLE CONNECTION ERRORS (this handler):
46
+ * - Emitted via EventEmitter when server kills an idle connection
47
+ * - Without a handler: crashes Node.js process
48
+ * - With this handler: logged and process continues
49
+ * - Examples: pg_terminate_backend during cleanup, server restart
50
+ *
51
+ * WHEN THIS FIRES:
52
+ * - pgpm test-packages creates temp databases, deploys, then drops them
53
+ * - Dropping requires pg_terminate_backend() to kill active connections
54
+ * - Idle connections in the pool receive PostgreSQL error 57P01
55
+ * - This handler catches that expected cleanup error
56
+ *
57
+ * PostgreSQL error codes handled:
58
+ * - 57P01: admin_shutdown (terminating connection due to administrator command)
59
+ * This is EXPECTED during database teardown and logged at debug level.
60
+ *
61
+ * All other error codes are logged at error level for visibility but do not
62
+ * crash the process, allowing the test harness to continue and report results.
63
+ */
64
+ pgPool.on('error', (err) => {
65
+ if (err.code === '57P01') {
66
+ // Expected during database cleanup - log at debug level
67
+ log.debug(`Pool ${database} connection terminated (expected during cleanup): ${err.message}`);
68
+ }
69
+ else {
70
+ // Unexpected pool error - log at error level for visibility
71
+ // Note: This does NOT swallow query errors - those still throw via Promise rejection
72
+ log.error(`Pool ${database} unexpected idle connection error [${err.code || 'unknown'}]: ${err.message}`);
73
+ }
74
+ });
21
75
  lru_1.pgCache.set(database, pgPool);
22
76
  return pgPool;
23
77
  };