Skip to content

[Next.js/dylib] Preserve request/work AsyncLocalStorage through concurrent App Routes #8037

Description

@proggeramlug

Summary

Make the AsyncLocalStorage subset used by Next.js App Routes correct under the real AppRouteRouteModule.handle path, including concurrent requests and continuations. This is a scoped Next.js acceptance cut of the broader node:async_hooks backlog in #6764, not a duplicate request to complete all 113 parity failures.

The current lower-bound adapter calls the userland GET directly because Perry cannot yet rely on Next's private request/work-store machinery. That bypass must disappear before Perry can claim it runs Next.js.

Reproduction app (provided)

Use the exact pinned app and 21-request verifier attached to #8034. Do not invent a new context test.

The supplied handler reads Next's public headers() API before and after both:

  1. a dynamic import() continuation; and
  2. a setTimeout(..., 1) continuation.

The verifier launches 20 requests concurrently, each with a distinct x-request-id, and requires both reads to equal that request's ID. It then sends a POST as an additional lifecycle check.

BASE_URL=http://127.0.0.1:3100 npm run verify

Required implementation behavior

  • Enter through the generated production routeModule.handle; calling GET directly is invalid because it bypasses the stores being tested.
  • Support the AsyncLocalStorage instances Next wires for action, request, work, and work-unit state.
  • Preserve each store through direct promises, async/await, dynamic import initialization, microtasks, timers, stream callbacks, and route completion.
  • Restore the prior store after nested run() / exit() and after throws or rejections.
  • Clear request-owned state after the response completes; do not retain a request or leak its store into the next call.
  • Isolate concurrent requests even when they share one process, runtime provider, stdlib provider, and event loop.

Regression coverage

Add one focused parity fixture mirroring #8034's continuation sequence, then make the production fixture a dylib integration gate. The focused test should include nested stores, a rejected branch, and two interleaved IDs so failures localize below Next.js.

Update/check off the matching propagation/provider cases in #6764 as they become covered; this issue is complete when the Next route cut passes even if unrelated async_hooks provider tests remain.

Acceptance criteria

  • [Next.js/dylib] Add a pinned production App Route parity fixture and CI gate #8034's beforeAwait and afterAwait fields equal the correct request ID in all 20 concurrent responses.
  • 100 repetitions show zero cross-request contamination, missing store values, hangs, or retained requests.
  • A rejected request does not poison the next request's store.
  • The production test invokes AppRouteRouteModule.handle and contains no direct-handler compatibility path.
  • Relevant focused tests pass in executable and app-only dylib modes.

Baseline / references

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugConfirmed defect or regressionparityCompatibility gap with Node.js, ECMAScript, or the supported ecosystem

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions