Repository navigation
test(driver-sqlite-wasm): run the persistence suites' temp files on /dev/shm, so a flush's fsync stops waiting on the shard's other suites - #27245
Conversation
…dev/shm, so a flush's fsync stops waiting on the shard's other suites The on-write and flush cases timed out on Test Core shards because each flush's fsync queued behind unrelated suites' disk I/O. Point TMPDIR at a writable /dev/shm in this package's vitest config; the code path, the assertions and the 5 s budget are unchanged. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FEkQ5oKUikM4XcQpd1HJ6U
📓 Docs Drift Check2 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run. What this run could not see
Coarse fallback — 7 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin b6845716385e11d2620f5be034837d68ba5e9afb && git checkout b6845716385e11d2620f5be034837d68ba5e9afb
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin fbe344b3c537d944028e95e67aac2c81a2ae8426 2c4bfcec4122d5a1a77c8e3bf91805c15cc14062 && git checkout -B drift-repro fbe344b3c537d944028e95e67aac2c81a2ae8426 && git merge --no-ff 2c4bfcec4122d5a1a77c8e3bf91805c15cc14062
node scripts/docs-audit/affected-docs.mjs --json fbe344b3c537d944028e95e67aac2c81a2ae8426 |
席位核对ACCEPT · The maintainer's standing authorisation for landing reviewed PRs, verbatim: 「按照 pm-dispatch 规则复核过的都授权」. The maintainer pointed the dev thread at the failing test themselves (
Generated by Claude Code |
Requested by Leehom · project thread
Fixes #27076
Clause-②: no
Metadata-protocol: none
维护者速读
driver-sqlite-wasm这个包的 vitest 配置把测试进程的TMPDIR指到可写的/dev/shm(内存盘);机器上没有/dev/shm(macOS、Windows)就保持原样。只动了packages/drivers/driver-sqlite-wasm/vitest.config.ts一个文件,产品代码、用例、断言和 5 s 预算都没动。fsync,而fsync要排在同一台 CI 机器上其他测试套件的磁盘队列后面,所以本地 30 ms 的用例在分片上能拖到 5 s 以上。用例测的是驱动的落盘语义,不是邻居的磁盘有多忙。sync()照样调用),只是临时文件落在内存盘上;不发布任何东西(vitest.config.ts不在包的files[]里)。回滚即 revert。packages/drivers/driver-sqlite-wasm/vitest.config.ts(唯一改动,头部注释写了测量)。cd packages/drivers/driver-sqlite-wasm && pnpm exec vitest run,预期 39 个文件 746 条全过;在用例里打印os.tmpdir()会看到/dev/shm。What changes
packages/drivers/driver-sqlite-wasm/vitest.config.tsused to be the bare re-export ofvitest.preset.mts. It is now adefineConfigwith two keys:disableConsoleIntercept: true, restated from the preset:check-console-intercept-disarm.mjsjudges the preset in a config's place only for the bare re-export, so a config with its own key carries the disarm itself (node scripts/check-console-intercept-disarm.mjs→OK: 77 vitest-running package(s)).env: { TMPDIR: '/dev/shm' }when/dev/shmis writable,{}otherwise. Every test file in the package reaches its temp directory throughos.tmpdir()(mkdtempSync(join(tmpdir(), …)), 9 files), andos.tmpdir()readsTMPDIRon each call, so no test file changes.Every other key stays on vitest's defaults, as under the re-export.
Why the cases were slow (the cause)
The failing case, read from the full job log by the maintainer (card comment 6468136240):
SqliteWasmDriver (file persistence) > should persist data on-write, 5,026 ms,Test timed out in 5000ms, onTest Core (6/8); its siblingon-disconnecttook 4,236 ms. Run 39853791549 timed out five cases, all on on-write or flush paths (background-flush-failure×3,returning-persistUPDATE … RETURNING,durabilityatomic write).Each of those flushes ends in
WasmSqliteConnection.atomicWriteFile: write a sibling temp file,handle.sync(), rename. The case itself is about 30 ms on an idle disk (step probe: create 3, insert 1, flush 4, reopen + find 3, raw 8 KiBsync()1 ms). The time goes tosync()waiting behind other processes' writes on the same disk:on-writecaseTMPDIRon the disk (2 runs, base 24351cf)dd … conv=fsyncwriters,TMPDIRon the disk (3 runs)TMPDIR=/dev/shm(3 runs)The same set of cases that went red on CI is the set that inflates under disk load, and only those. CPU load alone does not do it: 8 runs of the whole suite beside 3 busy-loop processes kept every case under 0.6 s.
Why this is the test's correctness, not a budget
A case whose wall time is set by unrelated suites' disk I/O measures the runner, not the driver. On
/dev/shmthe same code runs,sync()andrename()included, and every assertion (bytes on disk, atomic rename with no leftover temp file, the serialized flush chain, the failure report and retry) is unchanged. The triage ruling holds: no budget raised, no case skipped, no fixture shrunk, no retry wrapper.Tests
Red on the base config, green on this head: 8 fsync writers, alternated, 3 rounds (head 2c4bfce)
Base leg:
node scripts/ablation-replace.mjsreplaced theenv:line withenv: {}(the pre-change behaviour: anchor 1 → 0, blob08fbf987a6e2→ea1e118ddf13; a probe case printedTMPDIR_SEEN=/tmpunder it andTMPDIR_SEEN=/dev/shmon head), ran the four persistence files, then restored (ok restored: blob == HEAD (08fbf987a6e2) and git diff HEAD is empty, checked after every round). Head leg: the committed config. All legs under 8dd if=/dev/zero bs=1M count=512 conv=fsyncwriters on the same disk, inside oneos-verify-lockhold (VERDICT command-exit 0, 236 s).Base round 2 reproduces the CI failure exactly (
should persist data on-write,Test timed out in 5000ms).Whole package, head 2c4bfce
pnpm --filter @objectstack/driver-sqlite-wasm testunderos-verify-lock: VERDICT command-exit 0,Test Files 39 passed (39),Tests 746 passed (746)./dev/shmholds no leftover after the run (the suites clean theirmkdtempdirectories as before).What was tried before the case was named (base 24351cf)
Alone ×2, beside 3 busy-loop CPU burners ×8, and the shard's real whole-package leg (the 10 packages of
Test Core (6/8),turbo run test test:repo --concurrency=4,OS_TEST_TIERS=queue) ×3: all 746/746 green. Those loads were CPU-heavy, not fsync-heavy, which is why none reproduced it.Acceptance notes
/dev/shmis writable in the cloud container these readings come from; I did not read a GitHub runner's mounts, so the shard's next run is the proof that it is used there. A host without a writable/dev/shmkeeps its own temp directory, so the config never errors and never changes behaviour there.Verification
Local, head
2c4bfcec, change setpackages/drivers/driver-sqlite-wasm/vitest.config.tsonly.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 42 commands; each run with its exit code captured before any pipe;--ranreconciliation:42 derived famil(ies) accounted for — 40 run, 2 NOT-MEASURED.pnpm check:dual-build-cjs-loadsandpnpm check:lean-entry-closureexit 3 (PREREQUISITE NOT MET: they need a full workspace build, which this card thread did not run). CI runs both.node scripts/check-plugin-teardown-shape.mjs --self-testexited 3 on the shallow clone, then 0 aftergit fetch --depth=1of its positive-control commit (48 cases pass).node scripts/check-console-intercept-disarm.mjs→ exit 0 (OK: 77 vitest-running package(s));pnpm exec eslint --no-inline-config packages/drivers/driver-sqlite-wasm→ exit 0;pnpm --filter @objectstack/driver-sqlite-wasm typecheck→ exit 0;node scripts/check-commit-card-trailers.mjs --range origin/main..HEAD→ exit 0.vitest.config.tsis not in the package'sfiles[](dist,README.md,CHANGELOG.md), so nothing publishes:skip-changeset.Human Minimum
packages/specholds no runtime logic. (not touched)pnpm lintpasses. (eslint scoped to the package, in Verification above)main, one pull request.skip-changeset)packages/spectouched: its generated artifacts are regenerated and committed. (not touched)content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.🤖 Generated with Claude Code
https://claude.ai/code/session_01FEkQ5oKUikM4XcQpd1HJ6U
Generated by Claude Code