Skip to content

feat(server-utils): Restore caller context for callback tracing channels - #21863

Merged
logaretm merged 5 commits into
developfrom
feat/tracing-channel-callback-context
Jun 30, 2026
Merged

feat(server-utils): Restore caller context for callback tracing channels#21863
logaretm merged 5 commits into
developfrom
feat/tracing-channel-callback-context

Conversation

@logaretm

@logaretmlogaretm commented Jun 30, 2026

Copy link
Copy Markdown
Member

bindTracingChannelToSpan bound the span store on start only. That covers the synchronous frames and traces run through tracePromise. In general it covers start wrapped continuations.

We noticed that this doesn't work well for some callback-based traced calls, where asyncStart can run in a detached context. The main difference between promise-based traced calls and callback-based is callback continuations are run outside the start runStores callback. So adding a context rebind for asyncStart would fix that, and would be a safe change overall.

I used lru-memoizer as a POC to test this out. It creates no span, all it wants is the context rebind which is what the helper does anyways but was missing the asyncStart for that case specifically. With these changes we can drop the hand rolled logic.

`bindTracingChannelToSpan` only bound the span store on `start`, which covers
the synchronous frame but not a callback the library dispatches from a detached
async context (e.g. a socket data handler or a `setImmediate` drain). There,
native async-context propagation no longer reaches the caller, so work issued
inside the callback lost its parent.
Stash the caller's store at `start` and re-bind it on `asyncStart`, so
callback-style channels run their continuation in the caller's context — the
same way a promise's `.then` does natively. It's inert for promise channels,
which `publish` `asyncStart` rather than `runStores` it.
Migrate the lru-memoizer subscriber onto the helper (`getSpan` returns
`undefined`, so no span is created — it only needs the context rebind),
dropping its hand-rolled callback re-wrapping.
@github-actions

github-actionsBot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

PathSize% ChangeChange
@sentry/browser27.62 kB--
@sentry/browser - with treeshaking flags26.05 kB--
@sentry/browser (incl. Tracing)46.07 kB--
@sentry/browser (incl. Tracing + Span Streaming)47.82 kB--
@sentry/browser (incl. Tracing, Profiling)50.84 kB--
@sentry/browser (incl. Tracing, Replay)85.31 kB--
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags74.91 kB--
@sentry/browser (incl. Tracing, Replay with Canvas)89.99 kB--
@sentry/browser (incl. Tracing, Replay, Feedback)102.67 kB--
@sentry/browser (incl. Feedback)44.8 kB--
@sentry/browser (incl. sendFeedback)32.42 kB--
@sentry/browser (incl. FeedbackAsync)37.55 kB--
@sentry/browser (incl. Metrics)28.68 kB--
@sentry/browser (incl. Logs)28.93 kB--
@sentry/browser (incl. Metrics & Logs)29.61 kB--
@sentry/react29.41 kB--
@sentry/react (incl. Tracing)48.38 kB--
@sentry/vue32.85 kB--
@sentry/vue (incl. Tracing)47.93 kB--
@sentry/svelte27.64 kB--
CDN Bundle30.02 kB--
CDN Bundle (incl. Tracing)48.02 kB--
CDN Bundle (incl. Logs, Metrics)31.58 kB--
CDN Bundle (incl. Tracing, Logs, Metrics)49.35 kB--
CDN Bundle (incl. Replay, Logs, Metrics)70.79 kB--
CDN Bundle (incl. Tracing, Replay)85.51 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics)86.79 kB--
CDN Bundle (incl. Tracing, Replay, Feedback)91.32 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics)92.56 kB--
CDN Bundle - uncompressed89.42 kB--
CDN Bundle (incl. Tracing) - uncompressed145.35 kB--
CDN Bundle (incl. Logs, Metrics) - uncompressed94.12 kB--
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed149.32 kB--
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed218.66 kB--
CDN Bundle (incl. Tracing, Replay) - uncompressed264.36 kB--
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed268.32 kB--
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed278.06 kB--
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed282.01 kB--
@sentry/nextjs (client)50.76 kB--
@sentry/sveltekit (client)46.46 kB--
@sentry/core/server77.75 kB--
@sentry/core/browser64.06 kB--
@sentry/node-core61.47 kB+0.01%+1 B 🔺
@sentry/node122.85 kB+0.03%+28 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection)69.95 kB--
@sentry/node/light50.45 kB+0.01%+1 B 🔺
@sentry/node - without tracing73.2 kB+0.01%+1 B 🔺
@sentry/aws-serverless84.09 kB-0.01%-1 B 🔽
@sentry/cloudflare (withSentry) - minified180.62 kB--
@sentry/cloudflare (withSentry)446.93 kB--

View base workflow run

@logaretm
logaretm marked this pull request as ready for review June 30, 2026 18:29
@logaretm
logaretm requested a review from a team as a code ownerJune 30, 2026 18:29
@logaretm
logaretm requested review from JPeer264, andreiborza, isaacs and mydea and removed request for a teamJune 30, 2026 18:29

@cursorcursorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 910fdfe. Configure here.

Comment threadpackages/server-utils/src/tracing-channel.ts
… caller context
The asyncStart producer used `data._sentryCallerStore ?? asyncLocalStorage.getStore()`.
When the caller had no active store, `_sentryCallerStore` is `undefined` and the
fallback bound whatever was ambient at callback time — for a callback dispatched
from a pooled socket handler, that can be another request's store. `start` always
runs first and sets `_sentryCallerStore`, so return it verbatim (no fallback),
matching the synchronous path: no caller context restores to none, not a foreign one.

@isaacsisaacs left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works, and makes the mysql integration work. Will update pg PR once these two land.

@logaretm
logaretm merged commit e7c24a5 into developJun 30, 2026
547 of 552 checks passed
@logaretm
logaretm deleted the feat/tracing-channel-callback-context branch June 30, 2026 22:37
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@logaretm@isaacs