fix(next): route global drain through next after() to survive prerender - #660
Open
evlogai[bot] wants to merge 1 commit into
Open
fix(next): route global drain through next after() to survive prerender#660evlogai[bot] wants to merge 1 commit into
evlogai[bot] wants to merge 1 commit into
Conversation
Contributor
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
|
Thank you for following the naming conventions! 🙏 |
commit: |
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 join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Fixes #654. The global
log.*drain configured increateInstrumentationstarted inline in the emitting context. During Next Cache Components prerender, the prerender pass rejects in-flight work when it completes, so the fire-and-forget drainfetch()could be cancelled mid-send (HANGING_PROMISE_REJECTION) and adapters loggedFailed to send events.The fix wraps the global drain so its work is deferred through Next's
after(): the event is emitted synchronously, but the drain runs in a post-response context that outlives the prerender pass.Changes
packages/evlog/src/next/instrumentation-create.tsresolveAfter(): dynamically importsafterfromnext/server, caches the result, and returnsnullwhen unavailable (older Next versions, or an import failure), so nothing breaks outside Cache Components apps.createLifecycleSafeDrain(): wraps the configured drain; whenafterresolves, the drain invocation is submitted toafter(...)instead of running inline. Falls back to the previous inline behavior whenafteris missing orafter()throws synchronously.register()wires the wrapped drain asconfig.drain.packages/evlog/test/next/instrumentation-drain.test.tscovering three modes:afteravailable (drain deferred, delivered from the after callback),afterthrowing (inline fallback),aftermissing (inline fallback).instrumentation.test.tsdelegation assertion updated for the wrapper.evlogpatch.Checks
pnpm run lint: passpnpm run typecheck: passpnpm run test: pass (all workspace packages, evlognextsuite 80/80)Scope notes (honest limitations)
log.infoin a prerendered Server Component) fails earlier with this package version:isoNow()callsDate.now(), which Next rejects during prerender (unstable value 'Date.now()'). The drain-cancellation path was reached via a PPR-shaped page ("use cache"+ uncached fetch in<Suspense>).next start, the HANGING_PROMISE_REJECTION could not be reproduced end-to-end locally; runtime smoke tests showed successful delivery both before and after the fix. The deferral is proven by the unit tests, which exercise the actual wiring.register()(instrumentation) does not run innext buildprerender workers, so build-time prerender remains unaffected; the fix targets the runtime request path.Visual evidence
Before (
main): the regression test fails, the drain starts inside the emitting context.After (this branch): the drain is deferred through
after()and delivered from the post-response context.