cloudflare / cloudflare/vinext
Cache Components: release successful 'use cache' prerender abort listeners
- Dominant language
- TypeScript
- Stars
- 8.8k
- Forks
- 406
- Avg merge
- 2d 6h
- Merged PRs (30d)
- 120
Description
## Next.js Change
**Commit:** [`4a95af8`](https://github.com/vercel/next.js/commit/4a95af8084a681e3f26a847331ee5f2f8de52a42)
**PR:** [#97476](https://github.com/vercel/next.js/pull/97476)
## What changed
A fallback-shell `'use cache'` prerender can combine its dynamic-access and timeout signals with `AbortSignal.any()`. React attaches an abort listener to that composite during `prerender()`. After a successful render, clearing the timeout alone leaves the composite signal non-empty and retains React's listener (and the successful render) in Node.
Next.js now snapshots whether the timeout had already fired, then aborts the existing timeout controller after `clearTimeout()` when the composite signal was used. That abort releases React's listener. The snapshot preserves real timeout handling: cleanup-triggered aborts must not be treated as timeouts. Cache prerenders without a dynamic-access signal continue to use the direct timeout signal unchanged.
## Impact on vinext
vinext's Cache Components / `'use cache'` prerender path must release composite abort signals after a successful fallback-shell render. Otherwise long-lived Node dev/build processes can retain successful React prerenders and leak memory.
This complements, rather than duplicates, #2812: that issue prevents a cache fill that starts after the outer prerender was aborted from persisting an empty stream. This upstream change retains that guard and fixes listener cleanup for successful cache prerenders.
## Acceptance criteria
- [ ] When cache prerender combines dynamic-access and timeout signals, snapshot the timeout state before cleanup and abort the existing timeout controller after a successful render.
- [ ] Preserve the real-timeout error path; the cleanup abort must not be classified as a timeout.
- [ ] Keep direct timeout-signal behavior unchanged when no dynamic-access signal participates.
- [ ] Add a regression test that exercises a successful fallback-shell cache prerender and verifies the composite signal no longer retains React's abort listener.
- [ ] Retain #2812's after-prerender-abort guard so an empty cache entry is never persisted.
## Related
- #2812 — Cache fill after prerender abort must not poison entries
- vercel/next.js#97363 — upstream memory-retention report
Contributor guide
Research direction
Start at vinext's Cache Components / 'use cache' prerender path and inspect the existing #2812 after-prerender-abort guard. Add a regression test for a successful fallback-shell cache prerender with combined dynamic-access and timeout signals; done means the composite signal releases React's abort listener, real timeouts still error, direct timeout behavior is unchanged, and empty entries are not persisted after aborts.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- next.js, react, typescript
- Domain
- performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100