Repository navigation
fix(node): Register Vercel keep-alive listeners once - #25146
Merged
Merged
Conversation
Member
Author
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 2c481c7. Configure here.
chargome
marked this pull request as ready for review
October 7, 2026 16:43
chargome
requested review from
JPeer264,
andreiborza and
isaacs
and removed request for
a team
October 7, 2026 16:43
Lms24
approved these changes
Oct 7, 2026
JPeer264
approved these changes
Oct 8, 2026
Contributor
size-limit report 📦
|
A repeated init() registered another SIGTERM handler and response-finish subscriber per client, so replaced clients kept being flushed and every response got an extra waitUntil. Register the listeners once and flush the current client. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
chargome
force-pushed
the
fix/vercel-keepalive-repeated-init
branch
from
October 8, 2026 08:44
88a9c2d to
0ac8729
Compare
The keep-alive listeners are registered once per module instance, so a second init() on Vercel in the same test file no longer adds a SIGTERM listener. Give each Vercel test a fresh module instance. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
47 tasks
sentry-junior Bot
added a commit
to getsentry/toolkit
that referenced
this pull request
Oct 28, 2026
Move the fix from a telemetry.ts workaround into the existing @sentry/node-core patch. The light init() now registers one SIGTERM listener that flushes the latest client, mirroring getsentry/sentry-javascript#25146 for @sentry/node.
This was referenced Oct 28, 2026
sentry-junior Bot
added a commit
to getsentry/toolkit
that referenced
this pull request
Oct 28, 2026
Move the fix from a telemetry.ts workaround into the existing @sentry/node-core patch. The light init() now registers one SIGTERM listener that flushes the latest client, mirroring getsentry/sentry-javascript#25146 for @sentry/node.
BYK
added a commit
to getsentry/toolkit
that referenced
this pull request
Oct 28, 2026
When `VERCEL` is set, v10's `@sentry/node-core/light` `init()` adds a `SIGTERM` flush listener on every init and never removes it. Library-mode commands (`createSentrySDK`) call `initSentry()` per command, so in-process callers like `@sentry/bundler-plugins` hit `MaxListenersExceededWarning` during Vercel builds. v11 registers that listener once (getsentry/sentry-javascript#25146), and the rest of toolkit is already on v11, so the CLI now uses the workspace catalog `@sentry/core` and `@sentry/node` (11.6.0). The local `@sentry/node-core` and `@sentry/core` patches are gone. **SDK defaults.** The CLI now uses v11 defaults rather than recreating v10 behavior: - CLI mode uses `Sentry.init()` defaults, including `dataCollection` and `attachStacktrace`. The bundle didn't grow, because the bundled MCP code already pulled in v11's integrations. - The SDK's Http/NodeFetch integrations now create the `http.client` spans and inject `sentry-trace`/`baggage`. The CLI's own HTTP spans and manual header injection existed only because Bun's fetch didn't fire undici diagnostics channels, and the CLI now runs on Node. Response-cache hits are no longer wrapped in an `http.client` span, so `span.op:http.client` counts only requests that went out. Cache telemetry is unchanged: the response cache still emits `cache.get`/`cache.put` spans and the `cache.hit_rate` metric. Retries now show one span per attempt. - Library mode uses `getDefaultIntegrationsWithoutPerformance()` and leaves out integrations that hook the host process or its diagnostics channels (process handlers, HTTP/fetch, child process, worker threads, framework error handlers). Without those integrations, and on Bun (whose fetch doesn't fire undici diagnostics channels), the API client still creates its own `http.client` span and adds `sentry-trace`/`baggage`, so in-process callers keep request tracing. - Runtime channel injection is stripped at build time with the SDK's `__SENTRY_CHANNEL_INJECTION__` define, which is what the bundler plugins' `excludeChannelInjection` sets. That makes `index.cjs` ~72 KB smaller. `enableRuntimeChannelInjection: false` stays so unbundled dev and test runs behave the same. - `unknown_command` and `invalid_argument` are sent with `captureEvent` instead of `captureMessage`. With `attachStacktrace` on, `captureMessage` adds a synthetic exception, which marks the session errored. **Kept on purpose:** - `traceLifecycle: "static"`, because dashboards rely on scope tags on transactions and `beforeSendTransaction` scrubs `server_name`; both are dropped under v11's default span streaming. Moving to streamed spans should be its own change. - v11 removed `enableLogs`, so library mode drops logs via `beforeSendLog` instead. **Two v11 issues fixed here:** - v11 attaches the client to the current scope *before* switching to the AsyncLocalStorage context strategy. When `initSentry()` runs inside a still-pending pre-init span, as it does in the CLI's middleware chain, the client is lost, so commands like `sentry org list` sent no telemetry at all. `initSentry()` now re-binds the client after init. - `attachSentryReporter()` used a runtime `require()` that the bundler leaves unresolved, so shipped builds either failed it silently or, in library mode, could load the host app's `@sentry/node`. It's now a static import, which means shipped builds now forward consola logs, which they never did on v10. Repeated `initSentry()` calls with `VERCEL=1` keep one `SIGTERM` listener. Fixes #1692 <!-- junior-session-footer:start --> <!-- junior-conversation-id:slack%3AC010884QHLG%3A1793195293.030719 --> -- [View Junior Session](https://junior-prod.sentry.dev/conversations/slack%3AC010884QHLG%3A1793195293.030719) [[Sentry]](https://sentry.sentry.io/explore/conversations/slack%3AC010884QHLG%3A1793195293.030719/?project=4510944073809921) <!-- junior-session-footer:end --> --------- Co-authored-by: sentry-junior[bot] <264270552+sentry-junior[bot]@users.noreply.github.com> Co-authored-by: Burak Yigit Kaya <126780+BYK@users.noreply.github.com> Co-authored-by: Burak Yigit Kaya <burak.kaya@sentry.io>
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.
On Vercel, each
init()call registered anotherSIGTERMhandler and anotherhttp.server.response.finishsubscriber, each tied to its own client. A repeatedinit()replaces the client, so the old handlers kept flushing the replaced client and added an extrawaitUntilto every response. Surfaced by the Sentry review on #25125.The listeners are now registered once and flush whichever client is current. A replaced client is no longer flushed on
SIGTERM. That matchesdocs/repeated-init.md(repeatedinit()is unsupported, and buffered data stays on the old client), and it keeps the 500msSIGTERMwindow for the active client.