Skip to content

fix(rest): make async import-job cancellation actually stop the worker (#2824) - #3069

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-2824-verification-7f1524
Jul 16, 2026
Merged

fix(rest): make async import-job cancellation actually stop the worker (#2824)#3069
os-zhuang merged 1 commit into
mainfrom
claude/issue-2824-verification-7f1524

Conversation

@baozhoutao

Copy link
Copy Markdown
Contributor

Summary

Fixes#2824 — cancelling a running async CSV import had no effect: the job kept writing all rows and finished succeeded.

Root cause: with a synchronous storage driver (better-sqlite3 / wasm fallback), every await in the import row loop resolves as a microtask, so a 50k-row import monopolizes the Node event loop for its whole duration. The cancel route's HTTP handler (and every progress poll) never gets to run, so the in-memory flag that shouldCancel polls is never set.

Three-part fix:

  • runImport yields one macrotask (setImmediate) at every progress boundary (every progressEvery rows), so pending I/O — the cancel request, progress polls — gets serviced during a large import. Root-cause fix; also unblocks live progress for the wizard.
  • The worker's shouldCancel falls back to reading the durable job row: a cancel accepted by another process (or after a restart dropped the in-memory flag) still stops the worker.
  • A late cancel wins the terminal state: the final patch never overwrites the cancel route's durable cancelled with succeeded, and a job cancelled while still pending doesn't start at all.

Testing

  • 3 new unit tests (import-runner-cancel.test.ts): mid-loop cancel stops at the next checkpoint with truthful counts; no-cancel path unaffected; yield happens even without shouldCancel.
  • 3 new integration tests (import-job-integration.test.ts): mid-flight cancel via the route; out-of-band durable cancel (no in-memory flag); late-cancel terminal-state guard.
  • Negative verification: 4 of the 5 new tests fail on pre-fix code.
  • Full @objectstack/rest suite green (288 tests), build + DTS clean.
  • End-to-end showcase UI run on the rebuilt dist: live progress renders during a 50k import (dead at 0% before), clicking 取消导入 stops the worker mid-run (job cancelled at 17600/50000, row count stable afterwards), and an uncancelled control import still succeeds 50000/50000.

Known remaining (out of scope): the wizard shows 「已导入 0 条」 after cancel instead of the actual partial count — objectui frontend issue (objectui#2393).

Co-Authored-By: Claude noreply@anthropic.com

@vercel

vercelBot commented Jul 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentActionsUpdated (UTC)
specReadyReadyPreview, CommentJul 16, 2026 2:44pm

Request Review

@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation tests tooling size/m labels Jul 16, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/rest.

7 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/api/error-catalog.mdx(via @objectstack/rest)
  • content/docs/api/error-handling-server.mdx(via @objectstack/rest)
  • content/docs/api/index.mdx(via @objectstack/rest)
  • content/docs/plugins/index.mdx(via @objectstack/rest)
  • content/docs/plugins/packages.mdx(via @objectstack/rest)
  • content/docs/releases/implementation-status.mdx(via @objectstack/rest)
  • content/docs/releases/v12.mdx(via @objectstack/rest)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

@os-zhuang
os-zhuang merged commit 7bc9e79 into mainJul 16, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the claude/issue-2824-verification-7f1524 branch July 16, 2026 14:59
#2824)
On a synchronous storage driver (better-sqlite3 / wasm fallback) every await
in the import row loop resolves as a microtask, so a 50k-row import starved
the Node event loop for minutes: the cancel route's HTTP handler (and every
progress poll) never ran, the in-memory flag `shouldCancel` polls was never
set, and the job finished `succeeded` with all rows written despite the
user's cancel.
- runImport now yields one macrotask at every progress boundary so pending
I/O (cancel requests, progress polls) is serviced mid-import.
- The worker's shouldCancel also reads the durable job row as a fallback,
covering cancels accepted by another process or after a restart.
- A late cancel wins the terminal state: the worker's final patch no longer
overwrites the durable 'cancelled' with 'succeeded', and a job cancelled
while still pending doesn't start at all.
Co-Authored-By: Claude <noreply@anthropic.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

问题(导入):取消后,运行中的异步任务仍未停止

2 participants

@baozhoutao@os-zhuang