Skip to content

fix(next): route global drain through next after() to survive prerender - #660

Open
evlogai[bot] wants to merge 1 commit into
mainfrom
fix/654-drain-after
Open

fix(next): route global drain through next after() to survive prerender#660
evlogai[bot] wants to merge 1 commit into
mainfrom
fix/654-drain-after

Conversation

@evlogai

@evlogai evlogai Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #654. The global log.* drain configured in createInstrumentation started 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 drain fetch() could be cancelled mid-send (HANGING_PROMISE_REJECTION) and adapters logged Failed 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.ts
    • resolveAfter(): dynamically imports after from next/server, caches the result, and returns null when unavailable (older Next versions, or an import failure), so nothing breaks outside Cache Components apps.
    • createLifecycleSafeDrain(): wraps the configured drain; when after resolves, the drain invocation is submitted to after(...) instead of running inline. Falls back to the previous inline behavior when after is missing or after() throws synchronously.
    • register() wires the wrapped drain as config.drain.
  • Regression test in packages/evlog/test/next/instrumentation-drain.test.ts covering three modes: after available (drain deferred, delivered from the after callback), after throwing (inline fallback), after missing (inline fallback).
  • Existing instrumentation.test.ts delegation assertion updated for the wrapper.
  • Changeset: evlog patch.

Checks

  • pnpm run lint: pass
  • pnpm run typecheck: pass
  • pnpm run test: pass (all workspace packages, evlog next suite 80/80)
  • Regression test verified red before the fix (1 failed / 2 passed) and green after (3 passed), see evidence below.

Scope notes (honest limitations)

  • The literal repro shape from the issue (a plain log.info in a prerendered Server Component) fails earlier with this package version: isoNow() calls Date.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>).
  • On next 16.3.4 + evlog 2.28.1 with 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 in next build prerender 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.

Before After
before after

@vercel

vercel Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
evi Ready Ready Preview Sep 3, 2026 10:11pm UTC
evlog-docs Ready Ready Preview, v0 Sep 3, 2026 10:11pm UTC
evlog-render-lab Ready Ready Preview Sep 3, 2026 10:11pm UTC
evlog-telemetry Ready Ready Preview Sep 3, 2026 10:11pm UTC
just-use-evlog Error Error Sep 3, 2026 10:11pm UTC

Request Review

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Thank you for following the naming conventions! 🙏

@HugoRCD HugoRCD changed the title fix(evlog): route global drain through next after() to survive prerender fix(next): route global drain through next after() to survive prerender Sep 3, 2026
@pkg-pr-new

pkg-pr-new Bot commented Sep 3, 2026

Copy link
Copy Markdown
npm i https://pkg.pr.new/@evlog/cli@660
npm i https://pkg.pr.new/evlog@660
npm i https://pkg.pr.new/@evlog/nuxthub@660
npm i https://pkg.pr.new/@evlog/telemetry@660

commit: d61ba1e

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[bug] Next Cache Components: global HTTP drain fetch is cancelled after prerender

0 participants