Skip to content

ci: fix the flaky "database is locked" failure in the Deno job - #666

Open
alexander-akait wants to merge 3 commits into
mainfrom
claude/enhanced-resolve-660-qo14h7
Open

ci: fix the flaky "database is locked" failure in the Deno job#666
alexander-akait wants to merge 3 commits into
mainfrom
claude/enhanced-resolve-660-qo14h7

Conversation

@alexander-akait

Copy link
Copy Markdown
Member

Fixes #660

The failure

The deno leg of Cross-runtime fails intermittently with a random test suite dying before it runs:

FAIL test/exportsField.test.js
  ● Test suite failed to run
    database is locked
      at Object.has (ext:deno_webstorage/01_webstorage.js:1:898)

Root cause

jest clears mocks by walking the globals of the test sandbox and testing "_isMockFunction" in value on each one. Instrumenting the global catches the exact caller:

[STORAGE] localStorage has _isMockFunction
    at ModuleMocker.clearMocksOnScope (node_modules/jest-mock/build/index.js:868)
    at Runtime.resetModules  (jest-runtime)
    at Runtime.teardown      (jest-runtime)
    at tearDownEnv           (jest-runner)
    at processTicksAndRejections (ext:core/01_core.js:405:7)

jest-environment-node exposes localStorage in the sandbox, and in Deno that global is backed by a SQLite database under DENO_DIR which is opened on first access. That in check is the first access. Jest workers are separate Deno processes, so on a cold cache (CI never caches DENO_DIR) they all race to create that database and the losers throw database is locked, taking down whichever suite they were holding.

Reproduced standalone — 6 Deno processes opening localStorage at a synchronized instant:

database failed rounds
cold (created during the run) 2 / 10
warm (created beforehand) 0 / 10

Fix

Preload an in-memory Storage over localStorage/sessionStorage before jest starts. Jest workers inherit NODE_OPTIONS, so the shim reaches every process — which keeps the suite parallel instead of serialising it with --runInBand. Neither the library nor the suite uses web storage, so nothing needs to persist.

Measured on Deno 2.9.6 from a cold cache:

wall databases created tests
before 9.5s 1 (raced) 1522 pass
--runInBand 13.7s 1 1522 pass
this PR 9.0s 0 1522 pass

All four processes (parent + 3 workers) report the preload installed and DENO_DIR/location_data never appears, so the race is structurally impossible rather than merely unlikely.

A --require preload fails silently if it ever stops being applied, which would quietly restore the flake, so the job now also asserts that no web storage database was created. Tested both ways: passes with the shim, errors with NODE_OPTIONS unset.

Also: the bun job's --max-concurrency 1

Dropped as dead config. --max-concurrency caps how many test.concurrent() tests run at once; the suite declares none and the job doesn't pass --concurrent, so it never gated anything — on bun 1.4.2 (what latest resolves to today) the suite runs in 9.27s / 9.25s / 9.11s without it versus 9.44s with it. Bun also doesn't implement web storage at all (typeof localStorage === "undefined") and uses its own runner, so it never had the Deno problem.

It arrived in 6f87171, whose message ("ci: run bun concurrently") describes the opposite of what the diff did, and the bun job was green without it in the run immediately before. Happy to drop this commit if it was deliberate for something not visible in the logs.

Verification

lint:code, lint:types, fmt:check, lint:spellcheck and the Node suite (1522 pass) are all green. I could not run lint:special — it needs the tooling dependency, which this sandbox's proxy blocks from codeload.github.com; it only regenerates types from lib/, which this PR does not touch.

No changeset: CI-only change, matching how previous ci: commits were handled.

🤖 Generated with Claude Code

https://claude.ai/code/session_016aGHrb1YaEvaGwNELGEHjF


Generated by Claude Code

alexander-akait and others added 2 commits September 11, 2026 10:17
jest clears mocks by walking the globals of the test sandbox and testing
`"_isMockFunction" in value` on each one (`ModuleMocker.clearMocksOnScope`).
Its node environment exposes `localStorage` there, and in Deno that global
is backed by a SQLite database under `DENO_DIR` that is opened on first
access. Jest workers are separate Deno processes, so on a cold cache they
all race to create that database and the losers throw "database is locked",
failing a random test suite.

Preload an in-memory `Storage` over both web storage globals instead. The
workers inherit `NODE_OPTIONS`, so the shim reaches every process and the
database is never opened, which keeps the suite parallel. Neither the
library nor the suite uses web storage, so nothing needs to persist.

The preload would fail silently if it ever stopped being applied, so the
job now also asserts that no web storage database was created.

Fixes #660

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016aGHrb1YaEvaGwNELGEHjF
`--max-concurrency` caps how many `test.concurrent()` tests run at once.
The suite declares none and the job does not pass `--concurrent`, so the
flag never applied to anything: on bun 1.4.2 the suite runs in ~9.2s with
or without it.

It was added in 6f87171, whose message ("run bun concurrently") describes
the opposite of what it did, and the bun job was green without it in the
run right before. Removing it restores the intent and leaves behavior
unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016aGHrb1YaEvaGwNELGEHjF
@changeset-bot

changeset-bot Bot commented Sep 11, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: a1a5bb5

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@codspeed-hq

codspeed-hq Bot commented Sep 11, 2026

Copy link
Copy Markdown

Merging this PR will degrade performance by 6.54%

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 1 improved benchmark
❌ 1 regressed benchmark
✅ 140 untouched benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Mode Benchmark BASE HEAD Efficiency
Memory alias-wildcard-scan: 100+1 wildcard + 1 exact 1.5 KB 2.7 KB -46.84%
Memory deep-package-subpath: pkg/a/b/c requests (warm) 3.6 KB 2.2 KB +64.31%

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing claude/enhanced-resolve-660-qo14h7 (a1a5bb5) with main (c3eee53)

Open in CodSpeed

@codecov

codecov Bot commented Sep 11, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.14%. Comparing base (c3eee53) to head (a1a5bb5).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #666   +/-   ##
=======================================
  Coverage   98.14%   98.14%           
=======================================
  Files          49       49           
  Lines       10018    10018           
=======================================
  Hits         9832     9832           
  Misses        186      186           
Flag Coverage Δ
integration 98.14% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

`lint:types-test` type-checks `test/*.js` with the Node.js types only, so a
bare `typeof Deno` reference fails with TS2304. Probe the global with
`"Deno" in global` instead, which needs no declaration.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016aGHrb1YaEvaGwNELGEHjF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Fix CI

1 participant