fix(genui-a2ui-prompt): serialize build:api after build to avoid rspack cache race#2794
Conversation
…ck cache race genui#api-extractor depends on both //#build (which transitively triggers genui-a2ui-prompt#build) and genui-a2ui-prompt#build:api. Their scripts are identical (`rslib build`) and write to the same node_modules/.cache/rspack/<hash>/.temp directory, so turbo runs them concurrently and rspack's filesystem transaction lock aborts the second one with `Transaction already in progress by process N:rslib-node` (SIGABRT / exit 134), surfacing as a flaky `code-style-check` / `test-api` job. Add `dependsOn: ["build"]` to build:api so turbo runs them serially. The second rslib invocation still happens (turbo cache keys differ across tasks) but rspack's content-addressed cache is warm, so it's fast and no longer races.
|
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughConfiguration change to ChangesBuild Task Dependencies
Estimated code review effort🎯 1 (Trivial) | ⏱️ ~3 minutes Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Merging this PR will improve performance by 7.39%
|
| Benchmark | BASE |
HEAD |
Efficiency | |
|---|---|---|---|---|
| ⚡ | transform 1000 view elements |
43.3 ms | 40.3 ms | +7.39% |
Tip
Curious why this is faster? Comment @codspeedbot explain why this is faster on this PR, or directly use the CodSpeed MCP with your agent.
Comparing fix/genui-a2ui-prompt-rslib-cache-race (545fcc9) with main (baf40ba)
Footnotes
-
26 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports. ↩
|
Self-note from running this on PR #2793:
Cause: the So this fix is only half right — it kills the same-package rspack race in a2ui-prompt, but breaks the cross-package consumption order (a2ui imports from a2ui-prompt). The proper fix needs to cascade across packages too — either:
Pausing this PR; will rework before un-drafting. |
UI JudgeGEQI weighted score: 62.8 / 100 across 8 examples.
DetailsResult 1
Result 2
Result 3
Result 4
Result 5
Result 6
Result 7
Result 8
|
… race genui-a2ui-prompt's build:api was identical to build (both 'rslib build') and ran right after it, rewriting the same dist/. With no turbo edge between build:api and genui-cli#build (both only depend on #build), they ran concurrently: rslib cleans dist and emits index.js before index.d.ts, so genui-cli's tsc could read dist/ in the window where the .d.ts was missing -> TS2307/TS7016 'Cannot find module @lynx-js/genui-a2ui-prompt'. Point the genui api-extractor task at #build instead and remove the duplicate build:api. dist is now written once, before its consumers, so the race is gone. This also subsumes #2794: with no second 'rslib build' there is no concurrent rspack cache transaction to conflict. Verified locally: 'turbo api-extractor --filter=@lynx-js/genui* --force -- --local' reproduced the TS error before, and passes 3/3 after.
The lock existed only to serialize the in-script 'pnpm run build' calls (concurrent rslib builds corrupting rspack's cache, #2794). That in-script build is gone — turbo now builds each package before its api-extractor task — so the api-extractor script only runs the extractor binary, which writes per-package outputs with no shared mutable state. Concurrent runs need no mutual exclusion, so the link/reap lock (and its stale-reaping TOCTOU flagged in review) is removed entirely. Verified: forced 'turbo api-extractor -- --local' across the genui graph -> 26/26 tasks, all 'API Extractor completed successfully', 0 TS errors.
Summary
pnpm turbo api-extractorcan flake oncode-style-check/test-apiwith:The race:
@lynx-js/genui#api-extractor(inpackages/genui/turbo.json) depends on both//#buildand@lynx-js/genui-a2ui-prompt#build:api. The build chain triggersgenui-a2ui-prompt#build, and at the same time turbo schedulesgenui-a2ui-prompt#build:api. Both scripts are literallyrslib build, both produce the same rspack content hash, and both write to the samenode_modules/.cache/rspack/<hash>/.tempdirectory. rspack's own filesystem-storage transaction lock catches the conflict and aborts the second process withSIGABRT(exit 134).Fix: add
dependsOn: ["build"]tobuild:apiinpackages/genui/a2ui-prompt/turbo.jsonso turbo serializes the two.buildruns first, releases the rspack transaction on exit;build:apithen runs against a warm content-addressed cache.This is independent from the api-extractor lock TOCTOU fix in #2780 — that one fixed the JSON lockfile race in
run-api-extractor.mjs; this one is rspack's internal cache directory, surfaced by turbo's task graph rather than my lock script.Scoped to just
genui-a2ui-promptbecause that's the only package where I have a panic trace.openui/a2ui/a2ui-catalog-extractorshare the samebuild/build:apishape but usetscnotrslib, so they don't hit the rspack lock. If they start flaking we can extend the same dep.Test plan
code-style-check(which runspnpm turbo api-extractor) passes on this PR.test-api(which runspnpm turbo api-extractor -- --local).pnpm turbo api-extractor --filter=@lynx-js/genuistill produces the genui api reports without panic.Summary by CodeRabbit