fix(service-datasource): 补 vitest 超时配置覆盖空洞并复核 pool 用例并发隔离 (#6044) - #6101
Merged
Conversation
两条腿: 1. 覆盖空洞:本包此前没有任何 vitest 配置文件,全部用例吃 vitest 默认 5000ms —— #4856 把 testTimeout 逐包落在各包自己的 vitest.config.ts, 结构上覆盖不到没有该文件的本包。补 vitest.config.ts,testTimeout: 60_000 沿用 #4856 的取值不引入新数字,落在配置层使后续新增用例到达即被覆盖。 实测:flaky 用例(datasource-pool-support :122)是全文件第一个走到 `await import('@objectstack/driver-sql')`(knex)的用例,空载 1088ms, 对 5000ms 只有约 4.6 倍余量,队列全量并发下被吃掉即超时 —— 与签名吻合 (仅队列全量构建间歇红,受害 PR 自身全绿)。探针复核:6s 睡眠用例改前 以 "Test timed out in 5000ms" 变红、改后 6.2s 变绿,证明包级配置即生效层。 2. 并发隔离复核(分诊座位明令不许只调超时收尾):逐项排查文件/句柄/共享 状态 —— sqlite 构建落 :memory: 且生产路径不探测、不开连接、native addon 惰性不加载,零文件 I/O;Door-1 各用例 disconnect 销毁空 knex pool; Door-2/3 全部用 per-case fake;无临时文件、无端口、无跨用例可变共享状态。 结论:该红是真实一次性导入成本上的负载方差,不是泄漏,无需修隔离。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015a5qkLzpGXhLL2F5gvJ7dD
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckNo hand-written docs reference the 1 changed package(s). ✅ |
Contributor
Author
|
ESLint job 红 = base 侧共享损伤,非本 PR(services 座位 PM,一次性说明)
Generated by Claude Code |
hotlong
marked this pull request as ready for review
August 7, 2026 02:01
hotlong
enabled auto-merge
August 7, 2026 02:01
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 #6044
根因:#4856 的覆盖空洞,不是它已修签名的再现
packages/services/service-datasource没有任何 vitest 配置文件(包目录仅package.json/tsconfig.json/tsup.config.ts,test脚本是裸vitest run;仓库根也没有vitest.config.*/vitest.workspace.*,turbo.json与 workflows 不传任何超时参数——三层核查同 #4856 的方法),因此全部用例吃 vitest 默认 5000ms。#4856 修这类 flake 的方式是把testTimeout逐包落在各包自己的vitest.config.ts(spec 60s;driver-mongodb / qa-http-conformance 30s;metadata-fs / plugin-auth 10s),这个结构天然覆盖不到一个没有该文件的包——本包即是空洞。机制已实测钉死:
create()的 pool 检查(assertDatasourcePoolSupported,default-datasource-driver-factory.ts:345)发生在一切动态 import 之前,所以文件里前两个 reject 用例不加载任何重模块;sqlite WITHOUT a pool still builds(:122)是全文件第一个走到await import('@objectstack/driver-sql')(knex 及其依赖图)的用例,一次性模块求值成本全落在它身上:空载 1088ms 对 5000ms 只有约 4.6 倍余量(#4856 当时的 spec 案例是 1.46 倍),PR 分支单包跑绰绰有余;合并队列全量构建多包并发、I/O/CPU 争用时被吃掉即超时——与签名完全吻合(仅队列全量构建间歇红,受害 PR #5999 两次、#5973 一次,自身 CI 全绿且改动包不含该测试)。
修法:补本包
vitest.config.ts,结构照姊妹包(plugin-auth 形状:defineConfig+environment: 'node',本包测试显式import { … } from 'vitest'故不需要globals,不发明多余字段),testTimeout: 60_000沿用 #4856 的取值不引入新数字,落在配置层使后续新增用例到达即被覆盖。60s 对实测 1.1s 约 55 倍余量,吸收队列争用而不掩盖真挂起。并发隔离性复核结论(⛔ 分诊座位明令不许只调超时收尾——已逐项复核,未发现真实泄漏)
通读
datasource-pool-support.test.ts全部 27 个用例 + factory 构建路径(default-datasource-driver-factory.ts→sqlite-driver-fallback.ts→ driver-sqlSqlDriver),逐项::memory:(测试显式传入;buildSqlConnection的 fallback 也是:memory:),且dev: false走生产路径buildNative()不探测(sqlite-driver-fallback.ts:130-132)——不 connect、不跑查询,连内存库对象都不会创建,better-sqlite3 的 native addon 惰性到首次 acquire 才加载(本用例从未触发)。零文件 I/O,无临时路径 ⇒ 无跨用例路径碰撞面。(包内确用临时文件的是姊妹文件default-datasource-driver-factory.test.ts,其用mkdtempSync唯一路径 +afterAll清理,且 flaky 文件与它无共享路径。)SqlDriver构造期建 knex 实例(tarn pool 空,不开连接、不起定时器),Door-1 三个构建成功的用例均await handle.disconnect?.()→knex.destroy()销毁空 pool;postgres(db.internal)/ mysql(localhost:3306)用例 knex 惰性,从不拨号。两个 reject 用例在构造之前就 throw,无任何分配。无 socket、无 pool 句柄、无 native 句柄存活跨用例。(残余小点:disconnect 在断言之后无 try/finally,断言失败时 knex 实例不销毁——但空 tarn pool 无 OS 句柄/定时器,worker 随文件退出,构不成泄漏。)factory()每用例新建(工厂无模块态);模块级sqliteWithPool常量从不被就地修改(唯一变体走 spread 拷贝);Door-2/3 的svc()/adminHarness()每用例新建 engine/factory/records;dev: false显式传入,不依赖process.env,文件不改任何 env。唯一跨用例共享是 Node 模块缓存——by design,且正是「只有第一个重 import 用例慢」的原因。反向验证(方向预先判定)
6 秒睡眠探针用例(临时,未提交):改动前按预测以
Error: Test timed out in 5000ms.变红(证明默认层今天就是生效层)→ 加配置后按预测 6.20s 变绿(证明包级配置即生效层)。探针已删除,提交 diff 仅vitest.config.ts+ changeset 两个文件。验证清单
pnpm --filter @objectstack/service-datasource test(vitest run --reporter=verbose --maxWorkers=2):改前基线与改后各一轮,均 Test Files 12 passed (12) / Tests 230 passed (230);:122 用例耗时见上表,已佐证「5s 默认值对真实构建过紧」。pnpm --filter @objectstack/service-datasource typecheck:通过(tsc --noEmit 无输出)。pnpm --filter @objectstack/service-datasource build(tsup):成功(CJS/ESM/DTS)。pnpm lint通过;pnpm check:nul-bytesOK;pnpm check:published-files通过(本包files白名单为 dist/README/CHANGELOG,vitest.config.ts不进发布面,门自测亦确认白名单不收 test-harness config);pnpm check:type-check-coverageOK。.changeset/spec-vitest-testtimeout.md,patch + 「test configuration only」)给@objectstack/service-datasource加 patch changeset,Check Changeset 门以此为绿。packages/spec,未动content/docs/releases/。台账
落地后请队列管家清 #5810 台账对应行(签名:
datasource-pool-supportsqlite WITHOUT a pool)。Refs #4856(模式来源)/ #4850(同类根因)/ #5714 / PR #5954(用例来源)/ #5810(管家台账锚点)。
Generated by Claude Code