Skip to content

fix(connection): 后台 queryStore 动态 import 失败不再抛出未处理拒绝,修复 frontend-test 偶发 EnvironmentTeardownError - #10534

Merged
t8y2 merged 1 commit into
t8y2:mainfrom
zipg:codex/fix-ci-query-store-deferred-import
Sep 29, 2026
Merged

t8y2 merged 1 commit into
t8y2:mainfrom
zipg:codex/fix-ci-query-store-deferred-import

Conversation

@zipg

@zipg zipg commented Sep 28, 2026

Copy link
Copy Markdown
Collaborator

背景

#10513 的 CI 首次运行失败:frontend-test (1/2) 里 773 个测试文件、9310 条用例全部通过,作业却以 exit 1 结束,日志末尾是 4 个未处理拒绝:

Vitest caught 4 unhandled errors during the test run.
⎯⎯ Unhandled Rejection ⎯⎯
EnvironmentTeardownError: Cannot load '/apps/desktop/src/lib/sql/sqlDiagnostics.ts' imported from
/home/runner/work/dbx/dbx/apps/desktop/src/lib/sql/errorPosition.ts after the environment was torn down.
The last recorded callstack:
- .../lib/sql/sqlDiagnostics.ts
- .../lib/sql/errorPosition.ts
- .../stores/queryStore.ts
- .../stores/connectionStore.ts
- .../stores/__tests__/connectionStore.sidebarSearchFailure.spec.ts

 Test Files  773 passed (773)
      Tests  9310 passed (9310)
     Errors  4 errors

该失败与 PR 改动无关(本 PR 之前重跑即可变绿),属于会随机打红任意 PR 的既有 flaky。

根因

connectionStore.ts 的 invalidateConnectionMetadataLifetime() 里有一条 fire-and-forget 的动态 import:

void import("@/stores/queryStore").then(({ useQueryStore }) => {
  useQueryStore().staleConnectionDataTabMetadata(connectionId, database);
});

它依赖「稍后才解析出来的 chunk」,而且没有 catch。被动断链(markConnectionLost)、断开连接等路径都会走到这里:

  • 在浏览器里,chunk 加载失败就是一个未处理的 Promise 拒绝;
  • 在 Vitest 里,若该 chunk 在测试环境销毁后才返回,就会以 EnvironmentTeardownError 的形式变成未处理拒绝,被 Vitest 记为整个分片失败——这就是上面 Errors 4 errors + exit 1 的来源(侧栏搜索失败用例每个都会触发一次该清理)。

清理 data-tab freshness 本身是「尽力而为、晚一点清也安全」的路径(见原注释),所以它的失败应该被吞掉,而不是泄漏成未处理拒绝。

改动

  • apps/desktop/src/stores/connectionStore.ts:给这条 deferred import 补上 .catch(() => undefined)(与仓库内其它 fire-and-forget 调用一致),并补充注释说明为什么必须吞掉失败。
  • 新增 apps/desktop/src/stores/__tests__/connectionStore.metadataInvalidationImport.spec.ts:把 @/stores/queryStore 的 deferred import 变成必然失败,断言不再产生未处理拒绝。

实测

  • 修复前(仅隐藏 connectionStore.ts 的改动):该回归测试文件 Test Files 1 passed / Tests 1 passed / Errors 1 error,进程 exit 1,与 CI 的失败形态一致。
  • 修复后:exit 0,无未处理错误。
  • npx vitest run apps/desktop/src/stores apps/desktop/src/lib/sql → 104 files / 1128 tests 全通过。
  • vue-tsc --noEmit、oxlint、oxfmt --check 均通过。
  • 纯前端逻辑修复,无 UI 变化,故无截图。

被动断链(markConnectionLost)与断开连接会以 fire-and-forget 的方式
`void import("@/stores/queryStore")` 清理数据标签页的 tableMeta freshness。
该 import 依赖之后才解析的 chunk,失败时会产生未处理的拒绝:

  EnvironmentTeardownError: Cannot load '.../lib/sql/sqlDiagnostics.ts' imported
  from '.../lib/sql/errorPosition.ts' after the environment was torn down.

Vitest 把这类未处理拒绝记为整个分片失败:CI 上 t8y2#10513 的 frontend-test
773 个文件、9310 条用例全部通过,却因为 4 个未处理拒绝让作业 exit 1。

清理 freshness 本身是尽力而为、晚一点清也安全,所以失败必须被吞掉。

新增回归测试 connectionStore.metadataInvalidationImport.spec.ts:让 queryStore
的 deferred import 必然失败,验证不再泄漏未处理拒绝(修复前该文件 exit 1,
修复后 exit 0)。
@github-actions github-actions Bot added area/desktop Desktop application or Tauri shell bug Something isn't working labels Sep 28, 2026
@t8y2
t8y2 merged commit 9aa6d91 into t8y2:main Sep 29, 2026
27 checks passed
@t8y2

t8y2 commented Sep 29, 2026

Copy link
Copy Markdown
Owner

Thanks for the contribution! Merged in 9aa6d91, will be released in the next version.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/desktop Desktop application or Tauri shell bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants