Skip to content

fix(service-datasource): sqlite / sqlite-wasm 臂的 pool 声明改为响亮拒绝,不再静默丢弃 (#5714) - #5954

Merged
hotlong merged 1 commit into
mainfrom
claude/issue-5714-sqlite-pool-loud-reject
Aug 6, 2026
Merged

fix(service-datasource): sqlite / sqlite-wasm 臂的 pool 声明改为响亮拒绝,不再静默丢弃 (#5714)#5954
hotlong merged 1 commit into
mainfrom
claude/issue-5714-sqlite-pool-loud-reject

Conversation

@hotlong

@hotlong hotlong commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Fixes #5714

按维护者 2026-08-06 裁决(裁 B)实现:sqlite / sqlite-wasm 臂上的 pool 声明显式拒绝,并清理 app-crm 的无效声明。⛔ 未做 A(接通 + :memory: 强制 {1,1})。

前提复核(origin/main d9cac60,实测)

正文属实。worktree 内通过工厂真实构造(临时探针,已删):

sqlite      + pool{min:3,max:9}   knex.client.config.pool = {"createTimeoutMillis":15000}   live pool = {"min":1,"max":1}
sqlite-wasm + pool{min:3,max:9}   驱动自带 pool = {"min":1,"max":1}(作者声明未到达)
postgres    + pool{min:3,max:9}   knex config.pool = {"min":3,"max":9}                      live pool = {"min":3,"max":9}

与 issue 正文数字一致。examples/app-crmcrm_primary 是现网标本(声明 {min:1,max:5},实得单连接)。

为什么是拒绝而不是接通

knex 的 better-sqlite3 dialect 把 {min:1,max:1} 钉死是有意为之:每次取连接都 new Database(filename),两条 :memory: 连接是两个互不可见的独立数据库。照 max:5 接上去等于把一个 datasource 的数据劈成五份。SQLite 的连接策略不是平台能提供的旋钮,所以对一个它无法履行的声明,诚实的回答是拒绝 —— Prime Directive #12:在 producer 修元数据、在 authoring/publish 响亮拒绝,不在 consumer 容忍。

落点与时机(PM 机制假设的实测结论)

假设 1 成立 —— 拒绝可以完全落在 packages/services/service-datasource 内,未触 packages/spec,无 spec 产物重生成。新模块 datasource-pool-support.ts 持有谓词与消息,三道门调用:

位置 时机
启动自动连接 DatasourceConnectionService.connectDeclared 前置扫描 任何连接尝试之前,一次抛出点名所有违规 datasource
Setup 向导(runtime authoring) DatasourceAdminService.createDatasource / updateDatasource 落库之前(tryRegisterPool 会把失败吞成 warn,落库后再报等于没报)
驱动工厂 createDefaultDatasourceDriverFactory.create 构造前,最后一道门,覆盖直接调工厂的 host

假设 2 的选择与理由:时机取「构造/发布」,且前置扫描判所有已声明且 active !== false 的 datasource —— 不只判会被连接的那些。理由:ADR-0062 D2 门会跳过 managed + 无路由的 datasource,而 app-crm 标本恰好就是这个形状;它的 pool 和被连接者的一样被丢掉。active: false 跳过 —— 那是运维把坏 datasource 摘下线的开关,若连它也炸,等于把补救手段本身炸掉。

假设 3(消息即修法):消息只给一条修法(删掉 pool),说明原因,并说明该键在 postgres / mysql / mongo 上仍然有效。⛔ 不提任何环境变量、不建议换驱动;有单测把 OS_ALLOW_DRIVER_CONNECT_FAILURE / OS_*=1 / "switch|change the driver" 钉成禁止出现。

关键设计:这是 authoring 判定,不是 connect 失败 —— 它不走 handleFailure,所以 D5 降级策略与 OS_ALLOW_DRIVER_CONNECT_FAILURE 对它不适用、也不会被建议。那个逃生口是给「数据库连不上」这种关于世界的事实准备的;「驱动读不到的 pool」是关于元数据的事实,不该有环境变量能启动过去。

边界(刻意画的两条线)

反向验证(方向:预测 RED,实测 RED)

真实 boot 路径(最有说服力的一条):把 pool 块塞回 app-crm 并重建 artifact(第一次没重建,读到旧 artifact 假绿 —— 记录在此以免下一个人踩),pnpm dev:crm -- --fresh -p 39716 的启动被拒:

ERROR [AppPlugin] declared-datasource auto-connect failed for app 'com.example.crm':
Datasource 'crm_primary' declares a `pool` block, but the 'sqlite' driver does not read it: ...
Remove `pool` from this datasource declaration; it stays meaningful on the pooled drivers (postgres / mysql / mongo).
  at DatasourceConnectionService.assertDeclaredPoolsAreHonoured (...:540:36)
  at DatasourceConnectionService.connectDeclared (...:479:10)
  at AppPlugin.start (...)
✗ Plugin plugin.app.com.example.crm failed to start - rollback complete

注意消息里没有 OS_ALLOW_DRIVER_CONNECT_FAILURE,与相邻的 D5 fail-fast 文案形成对照 —— 这正是设计意图。删掉声明后同样的 boot 恢复绿:✓ Server is ready / Seeds: com.example.crm 28 rows

单测层:把谓词临时静音后跑新测试文件 —— 11 条拒绝钉子全红、15 条边界/回归钉子全绿(26 中 11 failed),证明钉子确实钉在行为上而非空转。

影响面清扫

按「规则的消费半径」扫,不是按改动包扫:全仓 sqlite|sqlite-wasm + pool 的声明只有两处 —— examples/app-crm(裁决点名)与 examples/app-showcase/src/system/datasources/index.ts(同形标本,一并清理)。showcase_external(sqlite,external)无 pool,不受影响;packages/runtime 的 standalone default datasource 不声明 pool。content/docs/data-modeling/drivers.mdx 里「honoured for every SQL driver」已成错误陈述,改成按驱动分述并说明 SQLite 上的拒绝。

验证

见 PR 讨论中的报告;逐门枚举了 .github/workflows/lint.yml 的闸门并在共享验证锁下前台执行。


Generated by Claude Code

… honour instead of dropping it (#5714)

`datasource.pool` reached a driver only from the arms that build a pooled
client (`postgres` / `mysql` via `buildSqlPool`, `mongo` via
`minPoolSize`/`maxPoolSize`). The `sqlite` and `sqlite-wasm` arms passed no
pool at all, so an author who sized their pool got the driver's own single
connection with no indication:

  sqlite   + pool{min:3,max:9}  knex.client.config.pool {"createTimeoutMillis":15000}  live {min:1,max:1}
  postgres + pool{min:3,max:9}  knex config.pool {"min":3,"max":9}                     live {min:3,max:9}

Wiring it through would be wrong rather than merely more work: knex's
better-sqlite3 dialect pins {min:1,max:1} on purpose, because two connections
to `:memory:` are two separate, mutually invisible databases. So the
declaration is rejected — maintainer ruling on #5714, option B.

New `datasource-pool-support.ts` holds the predicate and the message (a fix
instruction: delete the block; no escape hatch, no "change your driver"), and
three doors enforce it:

  - boot auto-connect (`connectDeclared`) refuses before any connection is
    attempted, naming every offender in one throw. It is an AUTHORING verdict,
    never routed through `handleFailure`, so OS_ALLOW_DRIVER_CONNECT_FAILURE
    does not apply and is not suggested. `active: false` is skipped.
  - the Setup wizard (`createDatasource`/`updateDatasource`) rejects the draft
    before the record is stored, with the same "only when this write touches
    the pairing" carve-out the #4410 config gate uses.
  - the driver factory rejects it as the last door.

`examples/app-crm` (the live specimen) and `examples/app-showcase` drop their
inert declarations; `content/docs/data-modeling/drivers.mdx` no longer claims
`pool` is honoured by every SQL driver.

The `memory` arm reads no pool either and is deliberately NOT in the rejected
set — widening the ruling's authoring-surface tightening is a triage decision;
filed as #5931 and named in the module comment.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015a5qkLzpGXhLL2F5gvJ7dD
@github-actions github-actions Bot added the size/l label Aug 6, 2026
@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

No hand-written docs reference the 1 changed package(s). ✅

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling labels Aug 6, 2026
@hotlong
hotlong marked this pull request as ready for review August 6, 2026 13:15
@hotlong
hotlong added this pull request to the merge queue Aug 6, 2026
Merged via the queue into main with commit 99d7a93 Aug 6, 2026
25 checks passed
@hotlong
hotlong deleted the claude/issue-5714-sqlite-pool-loud-reject branch August 6, 2026 13:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/l tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

datasource pool 声明在 sqlite / sqlite-wasm 驱动臂被静默丢弃(pg / mysql 生效)

2 participants