/** * S-131 —— SQL **引擎姿态**的运维读面(单一推导点,同 `memory-posture.ts` 的形制)。 * * ## 病 * * 「这台 worker 的事务读语义到底是什么」此前**任何读面都答不出来**:隔离级是服务器/会话变量,TiDB 的 * 事务模式是集群配置,而本仓每一条 `SELECT … FOR UPDATE` 的判据都以「加锁读是当前读」为前提。运维要 * 排查一次「为什么并发结果不对」,只能去登服务器读变量 —— 而那读的是**服务器**,不是**本仓的连接**。 * * ## 药 * * `sql-driver.ts` 的连接初始化在**每条池连接**上钉死这两件事并**回读复核**(`@contract txn.read-semantics`)。 * 本模块把那份读数拿出来,一次推导两个读面:operator 面(`GET /v1/diagnostics/wiring` 的 `sqlEngine` 段, * 全量)与消费端面(`GET /v1/capabilities` 的 `sql` 位,窄投影)。两面同源 —— 「诊断页说悲观、能力位说 * 乐观」在结构上不可能。 * * ## 两条诚实纪律(与 memory-posture 同源) * * ① **取实例真值,不按配置推断**:`facts` 是驱动在真连接上 `SET` 完之后**回读**的值,不是 env 里写了什么。 * ② **缺席就是缺席**:没有 SQL 后端(env-only / local 文件后端)⇒ `null`,不铸一个看起来像答案的空壳。 * * ## 拒启在哪一头 * * 不在这里 —— 在 `sql-driver.ts` 的连接初始化里(TiDB 乐观模式设不成悲观 / 隔离级复核不符 ⇒ 响亮抛)。 * 本模块在 boot 期借一条连接**触发**那次初始化,于是那句拒绝落在启动期而不是第一次业务写上。 */ import { type SqlEngineFacts } from "./plugins/sql-driver.js"; import type { Pool as MySqlPool } from "mysql2/promise"; import type { Pool as PgPool } from "pg"; /** 消费端窄投影(`GET /v1/capabilities` 的 `sql` 位)。`null` = 本部署没有 SQL 后端。 */ export interface SqlEngineCapability { engine: SqlEngineFacts["engine"]; isolation: string; txnMode: SqlEngineFacts["txnMode"]; } /** * Boot 期建立引擎事实:借一条池连接(初始化随之跑),再原样归还。返回一个 **live getter** —— 事实由 * 驱动持有,重连后它会被下一次初始化刷新,快照会说谎。 * * 抛出 = 拒启:连接初始化拒绝了这个后端(TiDB 乐观模式设不成悲观、隔离级复核不符、服务器太旧读不出 * `@@transaction_isolation`)。这条错**刻意不吞** —— 本仓所有 `FOR UPDATE` 判据都以它为前提。 */ export declare function establishSqlEnginePosture(pools: { mysqlPool?: MySqlPool | undefined; pgPool?: PgPool | undefined; }): Promise<(() => SqlEngineFacts | null) | undefined>; /** operator 面 → 消费端面的窄投影(`version` 是运维料,刻意不进能力位:它只对排障有意义)。 */ export declare function projectSqlEngineCapability(facts: SqlEngineFacts | null | undefined): SqlEngineCapability | null; //# sourceMappingURL=sql-engine-posture.d.ts.map