Skip to content

Cache Components: release successful 'use cache' prerender abort listeners #2996

Description

@ask-bonk

Next.js Change

Commit: 4a95af8
PR: #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 Cache Components: 'use cache' called after prerender aborts must error, not fill an empty entry (cache-poisoning fix) #2812's after-prerender-abort guard so an empty cache entry is never persisted.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    nextjs-trackingTracking issue for a Next.js canary change relevant to vinext

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions