@h-ai/reldb 0.1.0-alpha.68 → 0.1.0-alpha.70
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.en.md +1 -1
- package/README.ja.md +1 -1
- package/README.md +1 -1
- package/dist/index.js +27 -13
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/README.en.md
CHANGED
|
@@ -588,7 +588,7 @@ Common error codes:
|
|
|
588
588
|
| `HaiReldbError.TIMEOUT` | `hai:reldb:009` | MySQL acquisition deadline exceeded |
|
|
589
589
|
| `HaiReldbError.POOL_EXHAUSTED` | `hai:reldb:011` | MySQL acquisition queue is full |
|
|
590
590
|
|
|
591
|
-
Custom SQL methods in `BaseReldbCrudRepository` subclasses must check `await this.ensureReady()`. Construction starts table creation; service init must await candidate readiness before publication. PostgreSQL
|
|
591
|
+
Custom SQL methods in `BaseReldbCrudRepository` subclasses must check `await this.ensureReady()`. Construction starts table creation; service init must await candidate readiness before publication. PostgreSQL retries a single autocommit `CREATE TABLE/INDEX IF NOT EXISTS` once only for `23505/pg_class_relname_nsp_index` catalog contention (also `pg_type_typname_nsp_index` for tables), or a table row-type race reported as `42710` with server routine `heap_create_with_catalog` / `TypeCreate`, consistently through DDL and SQL entry points. A failed retry remains an error. Transactions, business uniqueness errors and other failures are not retried. Initial connection probing attempts temporary DNS `EAI_AGAIN` failures at most three times, with 250/500 ms delays; business SQL is never replayed.
|
|
592
592
|
|
|
593
593
|
## Production shared state
|
|
594
594
|
|
package/README.ja.md
CHANGED
|
@@ -588,7 +588,7 @@ if (!result.success) {
|
|
|
588
588
|
| `HaiReldbError.TIMEOUT` | `hai:reldb:009` | MySQL 接続取得の期限超過 |
|
|
589
589
|
| `HaiReldbError.POOL_EXHAUSTED` | `hai:reldb:011` | MySQL 接続待機キューが満杯 |
|
|
590
590
|
|
|
591
|
-
`BaseReldbCrudRepository` の派生クラスで独自 SQL を実行する前に `await this.ensureReady()` を確認します。構築時に建表を開始するだけなので、サービス init は候補の準備完了後に公開します。PostgreSQL
|
|
591
|
+
`BaseReldbCrudRepository` の派生クラスで独自 SQL を実行する前に `await this.ensureReady()` を確認します。構築時に建表を開始するだけなので、サービス init は候補の準備完了後に公開します。PostgreSQL の自動コミットによる単一の `CREATE TABLE/INDEX IF NOT EXISTS` は、`23505/pg_class_relname_nsp_index`(建表は `pg_type_typname_nsp_index` も対象)の競合、または建表時にサーバー routine が `heap_create_with_catalog` / `TypeCreate` である `42710` の行型競合に限り、DDL/SQL の両入口で一度だけ再実行します。再試行も失敗した場合はエラーを返します。トランザクション、業務の一意制約、その他の失敗は再試行しません。初期接続確認の一時 DNS エラー `EAI_AGAIN` は 250/500 ms 間隔で最大三回試行し、業務 SQL は再送しません。
|
|
592
592
|
|
|
593
593
|
## 本番の共有状態
|
|
594
594
|
|
package/README.md
CHANGED
|
@@ -588,7 +588,7 @@ if (!result.success) {
|
|
|
588
588
|
| `HaiReldbError.TIMEOUT` | `hai:reldb:009` | MySQL 连接获取超过截止期限 |
|
|
589
589
|
| `HaiReldbError.POOL_EXHAUSTED` | `hai:reldb:011` | MySQL 连接等待队列已满 |
|
|
590
590
|
|
|
591
|
-
派生 `BaseReldbCrudRepository` 的自定义 SQL 方法先检查 `await this.ensureReady()`;构造函数启动自动建表不等于仓库就绪,服务 init 必须等待候选仓库的就绪入口再发布。PostgreSQL
|
|
591
|
+
派生 `BaseReldbCrudRepository` 的自定义 SQL 方法先检查 `await this.ensureReady()`;构造函数启动自动建表不等于仓库就绪,服务 init 必须等待候选仓库的就绪入口再发布。PostgreSQL 自动提交的单条 `CREATE TABLE/INDEX IF NOT EXISTS` 仅对 `23505/pg_class_relname_nsp_index`(建表还包括 `pg_type_typname_nsp_index`)目录竞争,或建表时 `42710` 且服务端 routine 为 `heap_create_with_catalog` / `TypeCreate` 的行类型竞争重执行一次;重试仍失败则保留错误,DDL 与 SQL 入口一致;事务、业务唯一约束及其他错误不自动重试。初始化连接探测仅对临时 DNS 错误 `EAI_AGAIN` 最多尝试三次,间隔 250/500 ms;不重放业务 SQL。
|
|
592
592
|
|
|
593
593
|
## 生产共享状态
|
|
594
594
|
|
package/dist/index.js
CHANGED
|
@@ -5,8 +5,8 @@ import process from 'process';
|
|
|
5
5
|
import { createRequire } from 'module';
|
|
6
6
|
import { isIP } from 'net';
|
|
7
7
|
import { performance as performance$1 } from 'perf_hooks';
|
|
8
|
-
import { existsSync } from 'fs';
|
|
9
8
|
import { setTimeout as setTimeout$1 } from 'timers/promises';
|
|
9
|
+
import { existsSync } from 'fs';
|
|
10
10
|
import { Worker } from 'worker_threads';
|
|
11
11
|
|
|
12
12
|
// messages/en-US.json
|
|
@@ -2436,18 +2436,23 @@ function createPostgresProvider() {
|
|
|
2436
2436
|
const result = await queryFn(convertPlaceholders(sql), params);
|
|
2437
2437
|
return result.rows;
|
|
2438
2438
|
}
|
|
2439
|
+
async function executeStatement(sql, params) {
|
|
2440
|
+
try {
|
|
2441
|
+
return await pool.query(sql, params);
|
|
2442
|
+
} catch (error) {
|
|
2443
|
+
const kind = /^\s*CREATE\s+(TABLE|(?:UNIQUE\s+)?INDEX)\s+IF\s+NOT\s+EXISTS\s+/i.exec(sql)?.[1]?.toUpperCase();
|
|
2444
|
+
const single = !sql.trim().replace(/;$/, "").includes(";");
|
|
2445
|
+
const catalogConflict = typeof error === "object" && error !== null && "code" in error && (error.code === "23505" && "schema" in error && error.schema === "pg_catalog" && "constraint" in error && (error.constraint === "pg_class_relname_nsp_index" || kind === "TABLE" && error.constraint === "pg_type_typname_nsp_index") || kind === "TABLE" && error.code === "42710" && "routine" in error && (error.routine === "heap_create_with_catalog" || error.routine === "TypeCreate"));
|
|
2446
|
+
if (!kind || !single || !catalogConflict)
|
|
2447
|
+
throw error;
|
|
2448
|
+
return pool.query(sql, params);
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2439
2451
|
const rawDdl = {
|
|
2440
2452
|
async createTable(name, columns, ifNotExists = true) {
|
|
2441
2453
|
const quotedTable = quoteIdentifier(name);
|
|
2442
2454
|
const sql = buildDefaultCreateTableSql(pgBuildColumnSql, quotedTable, columns, ifNotExists);
|
|
2443
|
-
|
|
2444
|
-
await pool.query(sql);
|
|
2445
|
-
} catch (error) {
|
|
2446
|
-
if (!ifNotExists || typeof error !== "object" || error === null || !("code" in error) || error.code !== "23505" || !("constraint" in error) || error.constraint !== "pg_type_typname_nsp_index") {
|
|
2447
|
-
throw error;
|
|
2448
|
-
}
|
|
2449
|
-
await pool.query(sql);
|
|
2450
|
-
}
|
|
2455
|
+
await executeStatement(sql);
|
|
2451
2456
|
return ok(void 0);
|
|
2452
2457
|
},
|
|
2453
2458
|
async dropTable(name, ifExists) {
|
|
@@ -2470,7 +2475,7 @@ function createPostgresProvider() {
|
|
|
2470
2475
|
},
|
|
2471
2476
|
async createIndex(table, index, def) {
|
|
2472
2477
|
const sql = buildDefaultCreateIndexSql(quoteIdentifier, quoteIdentifier(table), quoteIdentifier(index), def);
|
|
2473
|
-
await
|
|
2478
|
+
await executeStatement(sql);
|
|
2474
2479
|
return ok(void 0);
|
|
2475
2480
|
},
|
|
2476
2481
|
async dropIndex(index, ifExists = true) {
|
|
@@ -2479,7 +2484,7 @@ function createPostgresProvider() {
|
|
|
2479
2484
|
return ok(void 0);
|
|
2480
2485
|
},
|
|
2481
2486
|
async raw(sql) {
|
|
2482
|
-
await
|
|
2487
|
+
await executeStatement(sql);
|
|
2483
2488
|
return ok(void 0);
|
|
2484
2489
|
}
|
|
2485
2490
|
};
|
|
@@ -2493,7 +2498,7 @@ function createPostgresProvider() {
|
|
|
2493
2498
|
return ok(rows[0] ?? null);
|
|
2494
2499
|
},
|
|
2495
2500
|
async execute(sql, params) {
|
|
2496
|
-
const result = await
|
|
2501
|
+
const result = await executeStatement(convertPlaceholders(sql), params);
|
|
2497
2502
|
return ok({ changes: result.rowCount ?? 0 });
|
|
2498
2503
|
},
|
|
2499
2504
|
async batch(statements) {
|
|
@@ -2627,7 +2632,16 @@ function createPostgresProvider() {
|
|
|
2627
2632
|
name: error instanceof Error ? "Error" : "UnknownError"
|
|
2628
2633
|
});
|
|
2629
2634
|
});
|
|
2630
|
-
|
|
2635
|
+
for (let attempt = 0; ; attempt++) {
|
|
2636
|
+
try {
|
|
2637
|
+
await pool.query("SELECT 1");
|
|
2638
|
+
break;
|
|
2639
|
+
} catch (error) {
|
|
2640
|
+
if (attempt >= 2 || typeof error !== "object" || error === null || !("code" in error) || error.code !== "EAI_AGAIN")
|
|
2641
|
+
throw error;
|
|
2642
|
+
await setTimeout$1(250 * (attempt + 1));
|
|
2643
|
+
}
|
|
2644
|
+
}
|
|
2631
2645
|
ready = true;
|
|
2632
2646
|
currentConfig2 = config;
|
|
2633
2647
|
logger3.info("Connected to PostgreSQL", { host: config.host, port: config.port, database: config.database });
|