[pull] canary from vercel:canary#1006
Merged
pull[bot] merged 2 commits intocode:canaryfrom Apr 28, 2026
Merged
Conversation
In a Node-runtime app route handler, `'use cache'` and fetch-cache stale-while-revalidate block the client response on the full background regeneration. A second request after the cache has gone stale does not return the stale value promptly. It waits the entire regen duration and then returns the freshly regenerated value, as described in issue #93146. The symptom is visible both on self-hosted Node and on Vercel Node. Edge route handlers were unaffected because they route through `edge-route-module-wrapper.ts`, which hands `pendingWaitUntil` directly to `evt.waitUntil` and never awaits it before the response completes. The root cause is independent of the `await ignoredStream.cancel()` change proposed in that issue, and also independent of #92636, which removed a separate blocking await inside `use-cache-wrapper.ts`. Both of those sit inside the `'use cache'` wrapper and affect how the stale entry is returned to the caller. The blocking that remains is in the transport layer and applies equally to any revalidation pushed into `pendingRevalidates` or `pendingRevalidateWrites`, not just `'use cache'`. #74164 migrated pending revalidate handling from the "keep the response stream open until the promise resolves" pattern introduced in #55978 and reinforced in #58744 to a conditional hand-off. If a platform `waitUntil` is available, revalidations run out of band via `ctx.waitUntil`. Otherwise `pipe-readable.ts` keeps `res.end` deferred until they settle, so minimal-mode deployments stay alive long enough for writes to persist. That migration landed correctly for app pages. `app-render.tsx` only assigns `options.waitUntil` in the `else` branch, so once `renderOpts.waitUntil` is present the `pipe-readable.ts` path receives nothing and does not block. The matching code for route handlers was added to `base-server.ts` in the same PR. It declared `let pendingWaitUntil = context.renderOpts.pendingWaitUntil`, cleared it when handing off to `ctx.waitUntil`, and then passed `context.renderOpts.pendingWaitUntil` into `sendResponse`. That is the unmutated property, not the cleared local. The local variable was never read. The hand-off therefore never displaced the pipe-readable await. The same promise was awaited twice. `ctx.waitUntil` registered it redundantly and `pipe-readable.ts` still held `res.end` open for the full revalidation. #80189 copied the block verbatim into `packages/next/src/build/templates/app-route.ts`, carrying the bug forward when response handling moved into the route template. Fixing it is a one-line change. Pass the local `pendingWaitUntil` (which is `undefined` once handed off) into `sendResponse`, so Node route handlers match both app pages and edge route handlers and the original intent of #74164 is restored. The existing `stale-cache-serving/route-handler` test in `app-static.test.ts` did not catch this. It only measured time-to-first-byte against the route start time, and first-byte was already fast pre-fix. Chunks are written before `pipe-readable.ts`'s close handler awaits `waitUntilForEnd`. Only the terminating chunk was delayed. The test is updated to also assert total response time against the route start. Pre-fix that new assertion fails at ~3000ms for the Node route handler variant while the page and edge variants continue to pass, which is exactly the scope of the regression. A new e2e test in `use-cache-swr` exercises the symmetric `'use cache'` path through a route handler fixture. fixes #93146 closes #93177 (incorrect fix) closes #93188 (incorrect fix)
The process of signing commits with GH API was stripping newlines. This configures that step to not strip newlines so lint doesn't fail. x-ref: https://github.com/vercel/next.js/actions/runs/25007903789/job/73240317094 <sub>Stack created with <a href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub>
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
See Commits and Changes for more details.
Created by
pull[bot] (v2.0.0-alpha.4)
Can you help keep this open source service alive? 💖 Please sponsor : )