fix(service-datasource): sqlite / sqlite-wasm 臂的 pool 声明改为响亮拒绝,不再静默丢弃 (#5714) - #5954
Merged
Merged
Conversation
… 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
Contributor
📓 Docs Drift CheckNo hand-written docs reference the 1 changed package(s). ✅ |
This was referenced Aug 6, 2026
hotlong
marked this pull request as ready for review
August 6, 2026 13:15
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #5714
按维护者 2026-08-06 裁决(裁 B)实现:sqlite / sqlite-wasm 臂上的
pool声明显式拒绝,并清理 app-crm 的无效声明。⛔ 未做 A(接通 +:memory:强制 {1,1})。前提复核(origin/main d9cac60,实测)
正文属实。worktree 内通过工厂真实构造(临时探针,已删):
与 issue 正文数字一致。
examples/app-crm的crm_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前置扫描DatasourceAdminService.createDatasource/updateDatasourcetryRegisterPool会把失败吞成 warn,落库后再报等于没报)createDefaultDatasourceDriverFactory.create假设 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」是关于元数据的事实,不该有环境变量能启动过去。边界(刻意画的两条线)
resolveDriverId认不出的 id(com.vendor.snowflake)原样放行 —— 与datasource.config闸门(datasource.config 至今无人校验:驱动 configSchema 是声明但完全惰性的(ADR-0049 enforce-or-remove,#4001 收尾发现) #4410)同一条线:「我们只校验我们能构造的」。memory不在拒绝集合内:它同样读不到pool(已实测:driver config = {"persistence":false},pool 未到达),但把它并进来是再一次收紧公开 authoring 面,超出本单裁决授权 —— 已单独立单 datasourcepool声明在 memory 驱动臂同样被静默丢弃(#5714 的姊妹臂,裁决未覆盖) #5931,并在模块注释里指名,让下一个读者看到这是刻意划界而非漏看。反向验证(方向:预测 RED,实测 RED)
真实 boot 路径(最有说服力的一条):把
pool块塞回 app-crm 并重建 artifact(第一次没重建,读到旧 artifact 假绿 —— 记录在此以免下一个人踩),pnpm dev:crm -- --fresh -p 39716的启动被拒:注意消息里没有
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的 standalonedefaultdatasource 不声明 pool。content/docs/data-modeling/drivers.mdx里「honoured for every SQL driver」已成错误陈述,改成按驱动分述并说明 SQLite 上的拒绝。验证
见 PR 讨论中的报告;逐门枚举了
.github/workflows/lint.yml的闸门并在共享验证锁下前台执行。Generated by Claude Code