Skip to content

[finding][services] datasource pool 还有两处静默丢弃:turso 整块、mongodb 的两个 timeout 键(#5714/#5931 拒绝集合覆盖不到的剩余面) #7243

Description

@os-zhuang

发现于 #6214 的台账精确化工作(把 packages/spec/liveness/datasource.json 的四行 pool.* 按驱动限定)。为了让台账不再高估 pool 的生效面,必须逐臂读一遍落地真值 —— 读出来的时候发现,#5714 / #5931sqlite / sqlite-wasm / memory 变成响亮拒绝之后,仍有两处「可写、被静默吞掉」的面。两处都不在本卡声明面内(收紧公开 authoring 面是契约决策),单独记录,严重度请分诊定。

台账已如实把两处记为「still dropped in silence」,不是漏看 —— 与 #5714 当初把 memory 记进模块注释是同一个做法。

事实一:turso 整块 pool 被静默丢弃

turso 不在 POOL_UNSUPPORTED_DRIVER_IDS 里,而 driverReadsDeclaredPool 对不在拒绝集合里的 id 一律答 true,所以工厂的拒绝闸门放行;turso 臂随后压根不读 spec.pool

  • packages/services/service-datasource/src/datasource-pool-support.ts:79 — 拒绝集合是 ['memory', 'sqlite', 'sqlite-wasm']
  • packages/services/service-datasource/src/default-datasource-driver-factory.ts:488-530turso 臂只把 url / authToken / encryptionKey / concurrency / syncUrl / sync 传给 TursoDriver,spec.pool 从不出现。

这一处落地代码自己已经写明,不是新发现,只是没有卡:datasource-pool-support.ts:90-99 原文 —

TursoDriverConfig has no min/max, only concurrency, and in local mode the driver is a better-sqlite3 SqlDriver — the very engine POOL_UNSUPPORTED_DRIVER_IDS rejects a pool block for. A declared pool on a turso datasource is therefore dropped in silence today. Changing that is a new rejection on an authoring surface and needs its own ruling; see the #6345 PR's follow-ups.

#6345 的验收评论(PR #6910)里没有立这张卡,所以「见 #6345 的 follow-ups」今天指向不存在的东西。本卡补上。

⚠️ 注意这一臂的形状比 sqlite 更难判:local 模式(file: url)下 TursoDriver 确实就是 better-sqlite3 SqlDriver,与 sqlite 臂同因;remote 模式(libsql://)下没有 knex 连接池、只有 concurrency。是「整臂拒绝」还是「按 url 模式分叉」,不是实现方能自己扩的。

事实二:mongodb 只读 min / max,两个 timeout 键落地无人接

mongodb 在拒绝集合之外、且确实读 pool —— 但只读两个键:

packages/services/service-datasource/src/default-datasource-driver-factory.ts:477-483
  const pool = (spec.pool ?? {}) as Record<string, unknown>;
  const driver = new MongoDBDriver({
    url: buildMongoUrl(spec),
    ...(cfg.database ? { database: cfg.database } : {}),
    ...(cfg.options && typeof cfg.options === 'object' ? { options: cfg.options } : {}),
    ...(typeof pool.min === 'number' ? { minPoolSize: pool.min } : {}),
    ...(typeof pool.max === 'number' ? { maxPoolSize: pool.max } : {}),
  });

pool.idleTimeoutMillispool.connectionTimeoutMillis 在这一臂不出现在任何位置。二者只在 buildSqlPool(:188-198,postgres / mysql)里被读。

所以一个 mongo 数据源写 pool: { max: 20, idleTimeoutMillis: 30000 } 会得到:maxPoolSize 生效、idleTimeoutMillis 无声消失。这是同一个块内的半生效,比整块丢弃更难被作者察觉 —— 「我的 pool 配置生效了」有一半是真的。

MongoClient 本身有对应旋钮(maxIdleTimeMS / connectTimeoutMSserverSelectionTimeoutMS),所以这一处与 sqlite/memory 不同类:不是「没有东西能承接」,而是「有东西能承接但没接」,候选修向里多一个「接上」的选项。

仓内标本

候选修向(不预判,列给分诊)

  1. turso:(a) 整臂并入 POOL_UNSUPPORTED_DRIVER_IDS(按 [skill] pm-dispatch: record two meta-judgments approved 2026-08-07 (silently-dropped declarations; two implementations of one operation) #6140 第 1 条 meta-裁定,「静默丢弃的键默认并入既有拒绝集合」的默认路径,需要为它写自己的 POOL_UNSUPPORTED_REASONS 条目);(b) 按 url 模式分叉判定;(c) 维持现状并在 spec 的 .describe() 里写明。
  2. mongodb 的两个 timeout:(a) 接上 MongoClient 的 maxIdleTimeMS / connectTimeoutMS(「实现」而非「拒绝」,ADR-0049 enforce-or-remove 的 enforce 边);(b) 做成按键的拒绝(现有 helper 是按驱动 id 全块拒绝,这需要新形状);(c) 维持现状并在台账/文档写明。

注意 #6140 的边界条款:「母单的理由被实测为臂特有时,默认不顺延」。sqlite 的理由(:memory: 会把一个数据源劈成多个库)对 mongo 的 timeout 键明显不适用,对 turso remote 也不适用 —— 所以两处都不能直接套用默认路径,这正是分别立卡的原因。

出处链

#5714(sqlite / sqlite-wasm 臂拒绝)→ #5931(memory 并入)→ #6214(spec 台账按驱动限定,PR #7242 —— 台账已把这两处如实记为 still-silent)。

去重

已搜索 issues/PR:turso poolmongodb pool minPoolSize maxPoolSizeidleTimeoutMillisdatasource pool —— 除 #5714 / #5931 / #6214 三张既有卡外无重复。#6268 / #7099 是 turso 的另两条缝(loader 双份、remote upsert),与本卡不同门。

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions