fix(ui): atomically write jsx-dev-runtime to fix flaky email build on multi-core#3583
fix(ui): atomically write jsx-dev-runtime to fix flaky email build on multi-core#3583omgovich wants to merge 1 commit into
email build on multi-core#3583Conversation
|
@omgovich is attempting to deploy a commit to the resend Team on Vercel. A member of the Team first needs to authorize it. |
🦋 Changeset detectedLatest commit: 54e2e83 The changes in this PR will be included in the next version bump. This PR includes changesets to release 3 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
There was a problem hiding this comment.
No issues found across 2 files
Confidence score: 5/5
- Automated review surfaced no issues in the provided summaries.
- No files require special attention.
Auto-approved: Fixes a cross-process race condition by writing to a temp file and atomically renaming into place. The change is isolated to one utility function, has a small blast radius, and includes a changeset for documentation.
Re-trigger cubic
… multi-core createJsxRuntime wrote the shared `jsx-dev-runtime.js` in place. Under `next build`'s multi-process static generation (e.g. Vercel), one worker process could read a half-written runtime produced by another — `jsxDEV` came out `undefined` and rendering threw `(void 0) is not a function` on a random template each build. The in-process promise cache only dedupes within a single process, so the cross-process race remained. Write the runtime to a unique temp file and atomically rename it into place, so concurrent readers always see a complete file.
e4a584f to
54e2e83
Compare
|
Closing for now as I couldn't reproduce the issue in 6.6.5. See the comment in the issue. |
Problem
email buildintermittently fails during static prerendering on multi-core builds (we hit it consistently on Vercel, never locally) with:The failing template is different every build but the error/digest are identical — a build-time race, not a faulty template.
Cause
createJsxRuntimeesbuilds a single shared file,node_modules/.react-email-jsx-runtime/jsx-dev-runtime.js, with a non-atomic in-place write.getEmailComponentthen reads that file (viajsxImportSource) to bundle each email.next buildprerenders pages across multiple worker processes, so one process can read a half-written runtime produced by another → itsjsxDEVexport isundefined→(void 0) is not a function.The existing
jsxRuntimePromiseCacheonly dedupes builds within a process; each worker process still builds the same on-disk file, so the cross-process race remains.Fix
Write the runtime to a unique temp file, then
fs.rename()it into place.rename()is atomic on the same filesystem, so concurrent readers always see a complete file. This complements the in-process cache (cache → no concurrent builds within a worker; atomic rename → no corruption across workers).Verification
Filesystem-level reproduction of the mechanism: in a tight concurrent write+read loop, the in-place write produced ~258 truncated reads; temp + rename produced 0.
Closes #3582
Summary by cubic
Fixes flaky
email buildcrashes on multi-core builds (e.g., Vercel) by atomically writing the sharedjsx-dev-runtime.js. This prevents half-written reads acrossnext buildworkers and makes prerendering reliable.fs.rename().jsxDEVundefinedand triggered(void 0) is not a functionduring prerendering.Written for commit 54e2e83. Summary will update on new commits.