test(wasi): add tokio runtime lifecycle regression test - #10379
Merged
graphite-app[bot] merged 1 commit intoJul 22, 2026
Merged
Conversation
Member
Author
How to use the Graphite Merge QueueAdd the label graphite: merge-when-ready to this PR to add it to the merge queue. You must have a Graphite account in order to use the merge queue. Sign up using this link. An organization admin has enabled the Graphite Merge Queue in this repository. Please do not merge from GitHub as this will restart CI on PRs being processed by the merge queue. This stack of pull requests is managed by Graphite. Learn more about stacking. |
shulaoda
marked this pull request as ready for review
July 22, 2026 06:29
graphite-app
Bot
changed the base branch from
07-20-fix_pair_tokio_runtime_acquire_and_release_on_wasm_to_prevent_premature_shutdown
to
graphite-base/10379
July 22, 2026 06:46
h-a-n-a
approved these changes
Jul 22, 2026
Member
Author
Merge activity
|
graphite-app
Bot
force-pushed
the
07-22-test_wasi_add_tokio_runtime_lifecycle_regression_test
branch
from
July 22, 2026 06:54
7e23056 to
ab367ba
Compare
graphite-app
Bot
force-pushed
the
graphite-base/10379
branch
from
July 22, 2026 06:54
6535e5d to
77c8ff9
Compare
graphite-app
Bot
force-pushed
the
07-22-test_wasi_add_tokio_runtime_lifecycle_regression_test
branch
from
July 22, 2026 06:55
ab367ba to
872262a
Compare
hyfdev
approved these changes
Jul 22, 2026
✅ Deploy Preview for rolldown-rs canceled.
|
### Description Follow-up to #10363, which must land first. Adds regression coverage for the `Access tokio runtime failed in spawn` crash class fixed there. This bug class was invisible to every existing CI test. The runtime acquire and release functions are no-ops on native targets, and no CI test actually executed the WASI binding: the WASI workflow builds the wasm binding and runs the stability test and the examples, but those load the native binding that the same job builds for tooling. So an unbalanced runtime release could only ever crash on StackBlitz, never in CI. The new `tests/wasi/runtime-lifecycle.mjs` is a plain node script following the `test:stability` pattern, wired into the WASI workflow right after the build step. It forces the real wasm binding and covers three sequences: - The #8411 shape: a build that gets closed (Vite bundling `vite.config.ts`), then a `DevEngine` is created and run. - The #8747 shape: a build that gets closed, then `watch()` runs until `BUNDLE_END`. - The invariant behind both: closing one consumer while a `DevEngine` is still alive must not tear the runtime down under the engine. Two details are load-bearing. `NAPI_RS_FORCE_WASI` is set to `error` inside the script before importing rolldown, because `true` silently falls back to the native binding when the wasi files are missing and the test would pass without testing anything. After the import the script also asserts via `require.cache` that `rolldown-binding.wasi.cjs` was really loaded. ### Verification Red and green were produced under identical conditions (same machine, same stable toolchain, napi 3.11.0 on both sides, wasm binding forced and asserted). On `main` (`aa73a6848`, without #10363) the test exits 1 in the first sequence with the exact issue signature: `Access tokio runtime failed in spawn` in napi's `tokio_runtime.rs`, followed by `RuntimeError: unreachable`. On top of #10363 all three sequences pass. To run locally: `pnpm build-wasi:debug` in `packages/rolldown` (dist only contains the wasi files when built with `TARGET=rolldown-wasi`), then `pnpm test:wasi-runtime` in `packages/rolldown/tests`. <!-- - What is this PR solving? Write a clear and concise description. - Reference the issues it solves (e.g. `fixes #123`). - What other alternatives have you explored? - Are there any parts you think require more attention from reviewers? Also, please make sure you do the following: - Read the Contributing Guidelines at https://rolldown.rs/contribution-guide/. - Check that there isn't already a PR that solves the problem the same way. If you find a duplicate, please help us review it. - Update the corresponding documentation if needed. - Include relevant tests that fail without this PR but pass with it. If the tests are not included, explain why. Thank you for contributing to Rolldown! -->
graphite-app
Bot
force-pushed
the
07-22-test_wasi_add_tokio_runtime_lifecycle_regression_test
branch
from
July 22, 2026 07:05
872262a to
ab000c4
Compare
graphite-app
Bot
deleted the
07-22-test_wasi_add_tokio_runtime_lifecycle_regression_test
branch
July 22, 2026 07:09
Brooooooklyn
added a commit
that referenced
this pull request
Jul 22, 2026
#10379 added tests/wasi/runtime-lifecycle.mjs to regression-cover the "Access tokio runtime failed in spawn" crash class (#8411/#8747), driving dev() and watch() on the WASI binding to exercise the shared *tokio* runtime's acquire/release refcount. This branch is tokio-free: the WASI binding runs the shared CurrentThread runtime owned by the N-API environment (the JS runtime leases are no-ops), so that refcount and its crash class cannot exist; and dev()/watch() are unsupported on the WASI artifact by design. The imported test therefore failed at the first dev() call with ERR_ROLLDOWN_UNSUPPORTED_RUNTIME_FEATURE. Adapted to the tokio-free equivalents while keeping the WASI-binding force-load + assertion that made the lane valuable: 1. repeated sequential build+close — runtime survives a consumer closing 2. two builds alive, close one — the other still works (#8411/#8747 invariant via the WASI-supported API) 3. dev() rejects synchronously with the unsupported-runtime code 4. watch() reports unsupported through its ERROR-event lifecycle Verified each assertion against the code: dev-engine.ts assertRuntimeFeature ('dev'), watch/index.ts + watch-emitter.ts failSetup emitting {code:'ERROR'}. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01T34fMrYCf2V13Mg8BKmnda
Merged
shulaoda
added a commit
that referenced
this pull request
Jul 29, 2026
## [1.2.1] - 2026-07-29 ### 🚀 Features - dev: support `hotUpdate` hook (#10305) by @h-a-n-a - dev: expose `disableWatcher` through the dev engine bindings (#10474) by @shulaoda - plugin: surface output-option callbacks in [PLUGIN_TIMINGS] (#10411) by @IWANABETHATGUY - `import.meta.ROLLDOWN_FILE_URL_<referenceId>_<urlId>` support to pass context to `resolveFileUrl` hook (#10297) by @sapphi-red - dev: skip the HMR update when a module's rebuilt output is unchanged (#10333) by @h-a-n-a - code-splitting: wrap strict execution order modules on demand (#10104) by @hyfdev - support `import.meta.ROLLDOWN_FILE_URL_*` (#10296) by @sapphi-red - implement `resolveFileUrl` plugin hook (#10291) by @sapphi-red - magic-string: support storeName on overwrite/update (#10312) by @IWANABETHATGUY ### 🐛 Bug Fixes - external: keep `__toESM` when the importing module is tree-shaken (#10516) by @IWANABETHATGUY - dev: resolve re-exports from externals through a real import (#10489) by @tbvjaos510 - code-splitting: route CJS barrel initialization per consumer (#10488) by @hyfdev - error: align filename-pattern diagnostics with Rollup's wording (#10501) by @IWANABETHATGUY - plugin: validate emitted prebuilt-chunk file names (#10399) by @IWANABETHATGUY - code-splitting: point a two-argument dynamic import at the chunk that holds the module (#10479) by @hyfdev - common: align is_path_fragment with Rollup's isPathFragment (#10398) by @IWANABETHATGUY - code-splitting: never name an internal chunk export `then` (#10480) by @hyfdev - code-splitting: avoid creating call-site-triggered entry facades (#10485) by @hyfdev - code-splitting: collect top-level eager order reasons in every strict build (#10463) by @hyfdev - code-splitting: let a cross-chunk dynamic importer carry the order trigger (#10456) by @hyfdev - code-splitting: avoid the dynamic-entry facade when the same-chunk collapse carries the trigger (#10433) by @hyfdev - binding: forward resolveId options.kind to callable builtin plugins (#10440) by @martijnwalraven - dev: keep the export name of `export * as ns from` (#10476) by @tbvjaos510 - code-splitting: only split an entry facade when something else can load its chunk (#10441) by @hyfdev - code-splitting: fold the runtime chunk back after order lowering (#10414) by @hyfdev - runtime: don't leave default undefined for cjs that fakes __esModule (#10453) by @IWANABETHATGUY - import-glob: escape generated string literals (#10438) by @shantanuraj - preserve-modules: don't assume every chunk mirrors a module (#10442) by @hyfdev - filter: treat missing hook inputs as non-matches, not panics (#10443) by @IWANABETHATGUY - code-splitting: keep CommonJS modules wrapped under strict execution order (#10405) by @hyfdev - code-splitting: align dynamicImports metadata with the rewritten import() specifier (#10430) by @hyfdev - dev: skip user plugin hooks for ?rolldown-lazy proxy modules (#10426) by @unknownjedi - treeshake: preserve side-effect-free spread arguments in manual-pure chains (#10432) by @IWANABETHATGUY - treeshake: preserve eagerly evaluated child effects of manual pure chains (#10427) by @Nic-Polumeyv - code-splitting: initialize pure definers behind star re-export barrels under strict execution order (#10409) by @hyfdev - resolveId: reject string `id` filters (must be a RegExp) (#10412) by @IWANABETHATGUY - code-splitting: collect eager order reasons for on-demand wrapping (#10387) by @hyfdev - rolldown: apply output.paths to CJS export-star of external modules (#10406) by @IWANABETHATGUY - dev: sourcemaps of lazily compiled chunks (#10386) by @tbvjaos510 - plugin: validate emitted file names at emitFile time (#10377) by @Nic-Polumeyv - guarantee tokio runtime release when close rejects (#10381) by @shulaoda - code-splitting: make strict transitive init registration deterministic and constant-time (#10320) by @hyfdev - pair tokio runtime acquire and release on wasm to prevent premature shutdown (#10363) by @shulaoda - don't body-demand modules from simulated facade chunk includes (#10351) by @IWANABETHATGUY - tracing: invalid RD_LOG filter and RD_LOG_OUTPUT=json no longer panic (#10343) by @Brooooooklyn - code-splitting: treat class definition-time global reads as order-sensitive (#10322) by @hyfdev - code-splitting: deconflict force-included runtime helper statements (#10336) by @hyfdev - binding: forward all missing parallel JS plugin hooks (#10345) by @Brooooooklyn - code-splitting: re-derive chunk exec order after the runtime sweep (#10334) by @hyfdev - types: add undefined to ExistingRawSourceMap optional properties (#10355) by @ocavue - magic-string: validate relocate ranges before rewiring (#10327) by @IWANABETHATGUY - add EMPTY_IMPORT_META warning for non-node CJS output (#10222) by @sapphi-red - call `resolveFileUrl` in a deterministic order (#10330) by @sapphi-red - magic-string: refuse repeated sendMagicString on a consumed instance (#10331) by @IWANABETHATGUY - magic-string: refuse to use a MagicString after sendMagicString consumed it (#10326) by @IWANABETHATGUY - magic-string: reject non-contiguous moves before rewiring the chunk list (#10311) by @IWANABETHATGUY - handle `./foo/bar` glob pattern the same as `foo/bar` (#10313) by @sapphi-red - magic-string: throw instead of panicking when append/prepend splits an edited chunk (#10301) by @IWANABETHATGUY - output: skip separator for empty hoisted functions (#10310) by @hyfdev - magic-string: don't report a change when edits cancel out (#10299) by @IWANABETHATGUY - sourcemap: map wrapped imported callees (#10288) by @hyfdev - magic-string: count positional inserts at index 0 on an empty source (#10306) by @IWANABETHATGUY - magic-string: return UTF-16 code units from length() (#10295) by @IWANABETHATGUY - output: skip separator for empty import prelude (#10289) by @hyfdev ### 🚜 Refactor - dev: make it easier to customize the runtime (#10338) by @sapphi-red - code-splitting: declare CJS carrier namespaces initializer-free (#10513) by @hyfdev - rollup-tests: avoid relying on `NODE_PATH` env var resolution (#10496) by @sapphi-red - code-splitting: derive symbol chunk ownership as pass-local link data (#10449) by @hyfdev - plugin: share asset emission helpers between copy_module and asset_module (#10450) by @Nic-Polumeyv - plugin: dedupe hook binding boilerplate (#10428) by @Nic-Polumeyv - plugin: share the oxc parse preamble between import-glob and dynamic-import-vars (#10452) by @Nic-Polumeyv - implement `GetAstBuilder` on visitor/pass types (#10424) by @overlookmotel - pass arrays to AST builder methods (#10419) by @overlookmotel - shorten AST builder code (#10418) by @overlookmotel - centralize final ESM init metadata (#10376) by @hyfdev - descriptor-based parallel-plugin detection (getParallelPluginInfo) (#10349) by @Brooooooklyn - remove AstFactory in favor of new_* construction traits (#10353) by @Boshen - enable oxc_ast's `disable_old_builder` feature (#10316) by @Boshen ### 📚 Documentation - development-guide: update config.json link line reference (#10523) by @dogledogle - clarify slash normalization for id hook filter (#10511) by @sapphi-red - code-splitting: record the thenable-namespace rule (#10502) by @hyfdev - clarify that `esmExternalRequirePlugin` must own its externals (#10439) by @TheAlexLichter - add troubleshooting entry for the @rolldown/binding-... resolution error (#10390) by @Nic-Polumeyv - add Code Splitting API reference category (#10382) by @vittorioexp ### ⚡ Performance - use VisitJsMut in JavaScript-only AST passes (#10507) by @Boshen - cache the resolved glob matcher for Id/ImporterId filters (#10410) by @IWANABETHATGUY - scope_hoisting: remove `alloc` field from `ScopeHoistingFinalizer` (#10425) by @overlookmotel - reduce string allocations (#10423) by @overlookmotel - hmr: remove unnecessary string allocations (#10422) by @overlookmotel - avoid allocating static strings via custom builder methods (#10421) by @overlookmotel - pass string literals to AST builder methods (#10420) by @overlookmotel - use VisitJs in JavaScript-only AST passes (#10396) by @Boshen - plugin: shrink erased plugin debug vtables (#10370) by @Boshen - reuse normalized path buffers (#10315) by @hyfdev ### 🧪 Testing - code-splitting: pin CJS barrel fallback triggers and flag-off equivalence (#10514) by @hyfdev - plugin: cover chunk fileName, absolute chunk name, and Windows drive names (#10400) by @IWANABETHATGUY - code-splitting: cover a single-chunk dynamic import of a wrapped module (#10505) by @hyfdev - file: remove the unused .dynamic_import fixture (#10481) by @hyfdev - treeshake: reduce manual-pure fixture to a minimal smoke test, move matrix to unit tests (#10436) by @IWANABETHATGUY - dev: run vite playgrounds under bundled dev (test-serve-bundled) (#10434) by @h-a-n-a - stop snapshots from silently hiding user code inside the runtime region (#10431) by @hyfdev - wasi: add tokio runtime lifecycle regression test (#10379) by @shulaoda - dev: expect preserved hot.data in hmr-whole-chain-dispose (#10380) by @h-a-n-a - code-splitting: pin flag-off wrapped-esm init emission (#10324) by @hyfdev - sourcemap: fix Windows-only failures in composition fixtures (#10368) by @shulaoda - generated-code: mark assert external in symbols_ns2 for deterministic output (#10339) by @hyfdev - code-splitting: cover entries-aware strict init cycle (#10307) by @hyfdev - make `just setup-vite` the only entry point that touches `vite/` (#10332) by @shulaoda - vite-tests: reuse the shared root vite checkout (#10325) by @shulaoda - test-dev-server: drop the vite submodule, track rolldown-canary (#10319) by @shulaoda - vite-tests: track the latest rolldown-canary rebased onto vite main (#10318) by @shulaoda - unify Vite in vite-test and test-dev-server (#10293) by @h-a-n-a ### ⚙️ Miscellaneous Tasks - scope the binding artifact download to `bindings-*` (#10525) by @shulaoda - deps: update napi (#10506) by @renovate[bot] - deps: update rollup submodule for tests to v4.62.3 (#10494) by @rolldown-guard[bot] - deps: upgrade oxc to 0.142.0 (#10497) by @shulaoda - deps: update test262 submodule for tests (#10495) by @rolldown-guard[bot] - deps: update github actions (#10460) by @renovate[bot] - deps: update rust crates (#10462) by @renovate[bot] - deps: update npm packages (#10461) by @renovate[bot] - metric: alert Discord when the metric workflow fails (#10447) by @IWANABETHATGUY - metric: mint a short-lived GitHub App token instead of a PAT (#10446) by @IWANABETHATGUY - repo: repair dangling CLAUDE.md symlink (#10451) by @hanayashiki - publint/package-metadata fixes and small correctness fixes (#10344) by @Brooooooklyn - deps: update dependency vite-plus to v0.2.6 (#10404) by @renovate[bot] - add Semgrep scan workflow (#10395) by @Boshen - enable Windows CI with a PR label (#10375) by @hyfdev - deps: upgrade oxc to 0.141.0 (#10373) by @camc314 - deps: update napi (#10369) by @renovate[bot] - deps: update test262 submodule for tests (#10367) by @rolldown-guard[bot] - deps: update taiki-e/install-action action to v2.83.3 (#10358) by @renovate[bot] - deps: update rust crates (#10357) by @renovate[bot] - deps: update npm packages (#10359) by @renovate[bot] - deps: update rust crate syn to v3 (#10362) by @renovate[bot] - deps: update rust crate oxc_sourcemap to v8.1.2 (#10356) by @renovate[bot] - deps: update dependency vite-plus to v0.2.5 (#10329) by @renovate[bot] - docs: migrate Netlify redirects to Void config (#10282) by @tux-tn - deps: update dependency rust to v1.97.1 (#10317) by @renovate[bot] - runtime: remove unused `runtime/index.js` (#10302) by @IWANABETHATGUY ### ❤️ New Contributors * @dogledogle made their first contribution in [#10523](#10523) * @tbvjaos510 made their first contribution in [#10489](#10489) * @martijnwalraven made their first contribution in [#10440](#10440) * @shantanuraj made their first contribution in [#10438](#10438) * @Nic-Polumeyv made their first contribution in [#10450](#10450) * @hanayashiki made their first contribution in [#10451](#10451) * @unknownjedi made their first contribution in [#10426](#10426) * @vittorioexp made their first contribution in [#10382](#10382) * @tux-tn made their first contribution in [#10282](#10282) Co-authored-by: shulaoda <165626830+shulaoda@users.noreply.github.com>
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.

Description
Follow-up to #10363, which must land first. Adds regression coverage for the
Access tokio runtime failed in spawncrash class fixed there.This bug class was invisible to every existing CI test. The runtime acquire and release functions are no-ops on native targets, and no CI test actually executed the WASI binding: the WASI workflow builds the wasm binding and runs the stability test and the examples, but those load the native binding that the same job builds for tooling. So an unbalanced runtime release could only ever crash on StackBlitz, never in CI.
The new
tests/wasi/runtime-lifecycle.mjsis a plain node script following thetest:stabilitypattern, wired into the WASI workflow right after the build step. It forces the real wasm binding and covers three sequences:vite.config.ts), then aDevEngineis created and run.Access tokio runtime failed in spawncrash on StackBlitz when using watch mode #8747 shape: a build that gets closed, thenwatch()runs untilBUNDLE_END.DevEngineis still alive must not tear the runtime down under the engine.Two details are load-bearing.
NAPI_RS_FORCE_WASIis set toerrorinside the script before importing rolldown, becausetruesilently falls back to the native binding when the wasi files are missing and the test would pass without testing anything. After the import the script also asserts viarequire.cachethatrolldown-binding.wasi.cjswas really loaded.Verification
Red and green were produced under identical conditions (same machine, same stable toolchain, napi 3.11.0 on both sides, wasm binding forced and asserted). On
main(aa73a6848, without #10363) the test exits 1 in the first sequence with the exact issue signature:Access tokio runtime failed in spawnin napi'stokio_runtime.rs, followed byRuntimeError: unreachable. On top of #10363 all three sequences pass.To run locally:
pnpm build-wasi:debuginpackages/rolldown(dist only contains the wasi files when built withTARGET=rolldown-wasi), thenpnpm test:wasi-runtimeinpackages/rolldown/tests.