Skip to content

Commit f0ed876

Browse files
committed
fix(nestjs): use waitForTracingChannelBinding properly
1 parent b918d9f commit f0ed876

1 file changed

Lines changed: 42 additions & 19 deletions

File tree

  • packages/server-utils/src/integrations/tracing-channel

packages/server-utils/src/integrations/tracing-channel/nestjs.ts

Lines changed: 42 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import * as diagnosticsChannel from 'node:diagnostics_channel';
22
import type { IntegrationFn, SpanAttributes } from '@sentry/core';
3-
import { debug, defineIntegration, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startInactiveSpan, startSpan } from '@sentry/core';
3+
import {
4+
debug,
5+
defineIntegration,
6+
SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,
7+
startInactiveSpan,
8+
startSpan,
9+
waitForTracingChannelBinding,
10+
} from '@sentry/core';
411
import { DEBUG_BUILD } from '../../debug-build';
512
import { CHANNELS } from '../../orchestrion/channels';
613
import { bindTracingChannelToSpan } from '../../tracing-channel';
@@ -164,6 +171,11 @@ const _nestjsChannelIntegration = (() => {
164171
return {
165172
name: INTEGRATION_NAME,
166173
setupOnce() {
174+
// `tracingChannel` is unavailable before Node 18.19 so do nothing in that case.
175+
if (!diagnosticsChannel.tracingChannel) {
176+
return;
177+
}
178+
167179
DEBUG_BUILD && debug.log('[orchestrion:nestjs] subscribing to @nestjs channels');
168180

169181
// App-creation span: `bindTracingChannelToSpan` opens the span on
@@ -172,24 +184,35 @@ const _nestjsChannelIntegration = (() => {
172184
//
173185
// `captureError: false` a failed bootstrap surfaces to the caller.
174186
// We just annotate the span.
175-
bindTracingChannelToSpan(
176-
diagnosticsChannel.tracingChannel<ChannelContext>(CHANNELS.NESTJS_APP_CREATION),
177-
data => {
178-
const moduleCls = data.arguments?.[0] as { name?: string } | undefined;
179-
return startInactiveSpan({
180-
name: 'Create Nest App',
181-
op: `${TYPE_APP_CREATION}.nestjs`,
182-
attributes: {
183-
[ATTR_COMPONENT]: NESTJS_COMPONENT,
184-
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN_NESTJS,
185-
[ATTR_NESTJS_TYPE]: TYPE_APP_CREATION,
186-
...(data.moduleVersion ? { [ATTR_NESTJS_VERSION]: data.moduleVersion } : {}),
187-
...(moduleCls?.name ? { [ATTR_NESTJS_MODULE]: moduleCls.name } : {}),
188-
},
189-
});
190-
},
191-
{ captureError: false },
192-
);
187+
//
188+
// `bindTracingChannelToSpan` uses `bindStore`, which needs the
189+
// async-context binding registered after integration `setupOnce`;
190+
// defer until it's available (matches the other channel subscribers).
191+
// Only this bind is deferred: it fires at `NestFactory.create`
192+
// (bootstrap), so a retry tick is fine. The plain `.subscribe` calls
193+
// below stay synchronous. The decorator channels fire at module-load /
194+
// decoration time (right after init), which a deferred subscription
195+
// could miss.
196+
waitForTracingChannelBinding(() => {
197+
bindTracingChannelToSpan(
198+
diagnosticsChannel.tracingChannel<ChannelContext>(CHANNELS.NESTJS_APP_CREATION),
199+
data => {
200+
const moduleCls = data.arguments?.[0] as { name?: string } | undefined;
201+
return startInactiveSpan({
202+
name: 'Create Nest App',
203+
op: `${TYPE_APP_CREATION}.nestjs`,
204+
attributes: {
205+
[ATTR_COMPONENT]: NESTJS_COMPONENT,
206+
[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN_NESTJS,
207+
[ATTR_NESTJS_TYPE]: TYPE_APP_CREATION,
208+
...(data.moduleVersion ? { [ATTR_NESTJS_VERSION]: data.moduleVersion } : {}),
209+
...(moduleCls?.name ? { [ATTR_NESTJS_MODULE]: moduleCls.name } : {}),
210+
},
211+
});
212+
},
213+
{ captureError: false },
214+
);
215+
});
193216

194217
// request_context + request_handler. `RouterExecutionContext.create`
195218
// runs once per route at setup: it receives `(instance, callback, ...)`

0 commit comments

Comments
 (0)