@zz1996/dbhub-dameng 0.1.5 → 0.1.7

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.
@@ -10,9 +10,12 @@ import {
10
10
  import dmdb from "dmdb";
11
11
  var DEFAULT_OPERATION_TIMEOUT_MS = 11e4;
12
12
  var RESOURCE_CLEANUP_TIMEOUT_MS = 2e3;
13
+ var CONNECT_RETRY_ATTEMPTS = 3;
14
+ var CONNECT_RETRY_DELAY_MS = 500;
13
15
  var DamengOperationTimeoutError = class extends Error {
14
- constructor(message) {
16
+ constructor(message, label) {
15
17
  super(message);
18
+ this.label = label;
16
19
  this.name = "DamengOperationTimeoutError";
17
20
  }
18
21
  };
@@ -94,59 +97,73 @@ var DamengConnector = class _DamengConnector {
94
97
  return new _DamengConnector();
95
98
  }
96
99
  async connect(dsn, initScript, config) {
97
- let createdPool = null;
98
- try {
99
- const connectionConfig = await this.dsnParser.parse(dsn, config);
100
- connectionConfig.poolAlias = this.buildPoolAlias();
101
- this.defaultSchema = connectionConfig.schema ?? null;
102
- this.poolAlias = connectionConfig.poolAlias;
103
- this.connectionTimeoutMs = config?.connectionTimeoutSeconds !== void 0 ? config.connectionTimeoutSeconds * 1e3 : 5e3;
104
- this.operationTimeoutMs = config?.queryTimeoutSeconds !== void 0 ? config.queryTimeoutSeconds * 1e3 : DEFAULT_OPERATION_TIMEOUT_MS;
105
- await this.closeRegisteredPool(connectionConfig.poolAlias);
106
- await this.validateDirectConnection(connectionConfig);
107
- createdPool = await dmdb.createPool(connectionConfig);
108
- this.pool = createdPool;
109
- await this.withConnection(async (conn) => {
100
+ for (let attempt = 1; attempt <= CONNECT_RETRY_ATTEMPTS; attempt += 1) {
101
+ let createdPool = null;
102
+ try {
103
+ const connectionConfig = await this.dsnParser.parse(dsn, config);
104
+ connectionConfig.poolAlias = this.buildPoolAlias();
105
+ this.defaultSchema = connectionConfig.schema ?? null;
106
+ this.poolAlias = connectionConfig.poolAlias;
107
+ this.connectionTimeoutMs = config?.connectionTimeoutSeconds !== void 0 ? config.connectionTimeoutSeconds * 1e3 : 5e3;
108
+ this.operationTimeoutMs = config?.queryTimeoutSeconds !== void 0 ? config.queryTimeoutSeconds * 1e3 : DEFAULT_OPERATION_TIMEOUT_MS;
109
+ connectionConfig.connectTimeout ?? (connectionConfig.connectTimeout = this.connectionTimeoutMs);
110
+ connectionConfig.queueTimeout ?? (connectionConfig.queueTimeout = this.connectionTimeoutMs);
111
+ await this.closeRegisteredPool(connectionConfig.poolAlias);
112
+ await this.validateDirectConnection(connectionConfig);
113
+ createdPool = await dmdb.createPool(connectionConfig);
114
+ this.pool = createdPool;
115
+ await this.withConnection((conn) => this.initializeSession(conn, initScript));
116
+ this.connectionConfig = connectionConfig;
117
+ this.initScript = initScript;
118
+ return;
119
+ } catch (error) {
120
+ if (createdPool) {
121
+ await this.closePoolQuietly(createdPool);
122
+ } else if (this.poolAlias) {
123
+ await this.closeRegisteredPool(this.poolAlias);
124
+ }
125
+ this.pool = null;
126
+ this.poolAlias = null;
127
+ this.connectionConfig = null;
128
+ this.initScript = void 0;
129
+ if (attempt < CONNECT_RETRY_ATTEMPTS && this.isRetryableConnectFailure(error)) {
130
+ console.error(
131
+ `Retrying Dameng source '${this.sourceId}' connection after transient failure (${attempt}/${CONNECT_RETRY_ATTEMPTS}): ${error instanceof Error ? error.message : String(error)}`
132
+ );
133
+ await this.delay(CONNECT_RETRY_DELAY_MS * attempt);
134
+ continue;
135
+ }
136
+ console.error("Failed to connect to Dameng database:", error);
137
+ throw error;
138
+ }
139
+ }
140
+ throw new Error("Failed to connect to Dameng database");
141
+ }
142
+ async initializeSession(conn, initScript) {
143
+ await this.executeWithTimeout(
144
+ conn,
145
+ "SELECT 1 AS OK",
146
+ [],
147
+ this.executeOptions()
148
+ );
149
+ if (!this.defaultSchema) {
150
+ const result = await this.executeWithTimeout(
151
+ conn,
152
+ "SELECT USER AS SCHEMA_NAME FROM DUAL",
153
+ [],
154
+ this.executeOptions()
155
+ );
156
+ this.defaultSchema = this.rowValue(result.rows?.[0], "SCHEMA_NAME") ?? null;
157
+ }
158
+ if (initScript) {
159
+ for (const statement of splitSQLStatements(initScript, "dameng")) {
110
160
  await this.executeWithTimeout(
111
161
  conn,
112
- "SELECT 1 AS OK",
162
+ statement,
113
163
  [],
114
- this.executeOptions()
164
+ this.executeOptions({ autoCommit: true })
115
165
  );
116
- if (!this.defaultSchema) {
117
- const result = await this.executeWithTimeout(
118
- conn,
119
- "SELECT USER AS SCHEMA_NAME FROM DUAL",
120
- [],
121
- this.executeOptions()
122
- );
123
- this.defaultSchema = this.rowValue(result.rows?.[0], "SCHEMA_NAME") ?? null;
124
- }
125
- if (initScript) {
126
- for (const statement of splitSQLStatements(initScript, "dameng")) {
127
- await this.executeWithTimeout(
128
- conn,
129
- statement,
130
- [],
131
- this.executeOptions({ autoCommit: true })
132
- );
133
- }
134
- }
135
- });
136
- this.connectionConfig = connectionConfig;
137
- this.initScript = initScript;
138
- } catch (error) {
139
- if (createdPool) {
140
- await this.closePoolQuietly(createdPool);
141
- } else if (this.poolAlias) {
142
- await this.closeRegisteredPool(this.poolAlias);
143
166
  }
144
- this.pool = null;
145
- this.poolAlias = null;
146
- this.connectionConfig = null;
147
- this.initScript = void 0;
148
- console.error("Failed to connect to Dameng database:", error);
149
- throw error;
150
167
  }
151
168
  }
152
169
  async disconnect() {
@@ -494,6 +511,20 @@ var DamengConnector = class _DamengConnector {
494
511
  });
495
512
  }
496
513
  async withConnection(fn) {
514
+ try {
515
+ return await this.withConnectionAttempt(fn);
516
+ } catch (error) {
517
+ if (!this.isConnectionAcquisitionFailure(error)) {
518
+ throw error;
519
+ }
520
+ console.error(
521
+ `Retrying Dameng source '${this.sourceId}' after connection acquisition failure: ${error instanceof Error ? error.message : String(error)}`
522
+ );
523
+ await this.ensurePool();
524
+ return this.withConnectionAttempt(fn);
525
+ }
526
+ }
527
+ async withConnectionAttempt(fn) {
497
528
  await this.ensurePool();
498
529
  const pool = this.pool;
499
530
  if (!pool) {
@@ -502,16 +533,15 @@ var DamengConnector = class _DamengConnector {
502
533
  let conn = null;
503
534
  let shouldRelease = true;
504
535
  try {
505
- conn = await this.withTimeout(
506
- pool.getConnection(),
507
- this.connectionTimeoutMs,
508
- "Dameng connection acquisition"
509
- );
536
+ conn = await this.acquireConnectionWithTimeout(pool);
510
537
  return await fn(conn);
511
538
  } catch (error) {
512
539
  if (error instanceof DamengOperationTimeoutError) {
513
540
  shouldRelease = false;
514
541
  this.markPoolUnhealthy(error.message);
542
+ } else if (!conn && this.isConnectionAcquisitionFailure(error)) {
543
+ shouldRelease = false;
544
+ this.markPoolUnhealthy(error instanceof Error ? error.message : String(error));
515
545
  }
516
546
  throw error;
517
547
  } finally {
@@ -520,6 +550,21 @@ var DamengConnector = class _DamengConnector {
520
550
  }
521
551
  }
522
552
  }
553
+ async acquireConnectionWithTimeout(pool) {
554
+ const acquisition = pool.getConnection();
555
+ try {
556
+ return await this.withTimeout(
557
+ acquisition,
558
+ this.connectionTimeoutMs,
559
+ "Dameng connection acquisition"
560
+ );
561
+ } catch (error) {
562
+ if (error instanceof DamengOperationTimeoutError) {
563
+ void acquisition.then((conn) => this.releaseConnectionQuietly(conn)).catch(() => void 0);
564
+ }
565
+ throw error;
566
+ }
567
+ }
523
568
  async ensurePool() {
524
569
  if (this.pool) {
525
570
  return;
@@ -581,7 +626,7 @@ var DamengConnector = class _DamengConnector {
581
626
  let timer;
582
627
  const timeout = new Promise((_, reject) => {
583
628
  timer = setTimeout(() => {
584
- reject(new DamengOperationTimeoutError(`${label} timed out after ${timeoutMs}ms`));
629
+ reject(new DamengOperationTimeoutError(`${label} timed out after ${timeoutMs}ms`, label));
585
630
  }, timeoutMs);
586
631
  });
587
632
  try {
@@ -614,6 +659,46 @@ var DamengConnector = class _DamengConnector {
614
659
  );
615
660
  }
616
661
  }
662
+ isConnectionAcquisitionFailure(error) {
663
+ if (error instanceof DamengOperationTimeoutError) {
664
+ return error.label === "Dameng connection acquisition";
665
+ }
666
+ const message = error instanceof Error ? error.message : String(error);
667
+ return [
668
+ "Connection request timeout in queue",
669
+ "Pool cannot open more connections",
670
+ "\u83B7\u53D6\u8FDE\u63A5\u8BF7\u6C42\u7B49\u5F85\u8D85\u65F6",
671
+ "\u8FDE\u63A5\u6C60\u5DF2\u8FBE\u5230\u6700\u5927\u8FDE\u63A5\u6570"
672
+ ].some((item) => message.includes(item));
673
+ }
674
+ isRetryableConnectFailure(error) {
675
+ if (error instanceof DamengOperationTimeoutError) {
676
+ return [
677
+ "Dameng direct connection",
678
+ "Dameng connection acquisition",
679
+ "Dameng SQL execution"
680
+ ].includes(error.label);
681
+ }
682
+ const message = error instanceof Error ? error.message : String(error);
683
+ return [
684
+ "ECONNRESET",
685
+ "ETIMEDOUT",
686
+ "ECONNREFUSED",
687
+ "socket hang up",
688
+ "Socket timeout",
689
+ "connect timeout",
690
+ "Connection request timeout in queue",
691
+ "Pool cannot open more connections",
692
+ "\u7F51\u7EDC\u901A\u8BAF\u8D85\u65F6",
693
+ "\u7F51\u7EDC\u901A\u4FE1\u5F02\u5E38",
694
+ "\u8FDE\u63A5\u8D85\u65F6",
695
+ "\u83B7\u53D6\u8FDE\u63A5\u8BF7\u6C42\u7B49\u5F85\u8D85\u65F6",
696
+ "\u8FDE\u63A5\u6C60\u5DF2\u8FBE\u5230\u6700\u5927\u8FDE\u63A5\u6570"
697
+ ].some((item) => message.includes(item));
698
+ }
699
+ delay(ms) {
700
+ return new Promise((resolve) => setTimeout(resolve, ms));
701
+ }
617
702
  executeOptions(extra = {}) {
618
703
  return {
619
704
  outFormat: dmdb.OUT_FORMAT_OBJECT,
package/dist/index.js CHANGED
@@ -1865,7 +1865,7 @@ var connectorModules = [
1865
1865
  { load: () => import("./sqlite-IOUAYHGE.js"), name: "SQLite", driver: "node:sqlite" },
1866
1866
  { load: () => import("./mysql-A43SL7UM.js"), name: "MySQL", driver: "mysql2" },
1867
1867
  { load: () => import("./mariadb-7F72IRB4.js"), name: "MariaDB", driver: "mariadb" },
1868
- { load: () => import("./dameng-DTI47UV6.js"), name: "Dameng", driver: "dmdb" }
1868
+ { load: () => import("./dameng-5KYI5JBK.js"), name: "Dameng", driver: "dmdb" }
1869
1869
  ];
1870
1870
  loadConnectors(connectorModules).then(() => main()).catch((error) => {
1871
1871
  console.error("Fatal error:", error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zz1996/dbhub-dameng",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "mcpName": "io.github.zuozh11/dbhub-dameng",
5
5
  "description": "Local fork of DBHub with Dameng/DM8 database connector support",
6
6
  "repository": {