Skip to content

Commit 5062ce1

Browse files
authored
feat(node): Migrate to domains used through AsyncContextStrategy (#7779)
1 parent 7987221 commit 5062ce1

File tree

21 files changed

+236
-419
lines changed

21 files changed

+236
-419
lines changed

packages/core/src/hub.ts

Lines changed: 2 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,7 @@ import type {
2020
TransactionContext,
2121
User,
2222
} from '@sentry/types';
23-
import {
24-
consoleSandbox,
25-
dateTimestampInSeconds,
26-
getGlobalSingleton,
27-
GLOBAL_OBJ,
28-
isNodeEnv,
29-
logger,
30-
uuid4,
31-
} from '@sentry/utils';
23+
import { consoleSandbox, dateTimestampInSeconds, getGlobalSingleton, GLOBAL_OBJ, logger, uuid4 } from '@sentry/utils';
3224

3325
import { DEFAULT_ENVIRONMENT } from './constants';
3426
import { Scope } from './scope';
@@ -54,7 +46,7 @@ export interface RunWithAsyncContextOptions {
5446
/** Whether to reuse an existing async context if one exists. Defaults to false. */
5547
reuseExisting?: boolean;
5648
/** Instances that should be referenced and retained in the new context */
57-
args?: unknown[];
49+
emitters?: unknown[];
5850
}
5951

6052
/**
@@ -95,10 +87,6 @@ export interface Carrier {
9587
*/
9688
integrations?: Integration[];
9789
extensions?: {
98-
/** Hack to prevent bundlers from breaking our usage of the domain package in the cross-platform Hub package */
99-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
100-
domain?: { [key: string]: any };
101-
} & {
10290
/** Extension methods for the hub, which are bound to the current Hub instance */
10391
// eslint-disable-next-line @typescript-eslint/ban-types
10492
[key: string]: Function;
@@ -561,11 +549,6 @@ export function getCurrentHub(): Hub {
561549
}
562550
}
563551

564-
// Prefer domains over global if they are there (applicable only to Node environment)
565-
if (isNodeEnv()) {
566-
return getHubFromActiveDomain(registry);
567-
}
568-
569552
// Return hub that lives on a global object
570553
return getGlobalHub(registry);
571554
}
@@ -621,34 +604,6 @@ export function runWithAsyncContext<T>(callback: (hub: Hub) => T, options: RunWi
621604
return callback(getCurrentHub());
622605
}
623606

624-
/**
625-
* Try to read the hub from an active domain, and fallback to the registry if one doesn't exist
626-
* @returns discovered hub
627-
*/
628-
function getHubFromActiveDomain(registry: Carrier): Hub {
629-
try {
630-
const sentry = getMainCarrier().__SENTRY__;
631-
const activeDomain = sentry && sentry.extensions && sentry.extensions.domain && sentry.extensions.domain.active;
632-
633-
// If there's no active domain, just return global hub
634-
if (!activeDomain) {
635-
return getHubFromCarrier(registry);
636-
}
637-
638-
// If there's no hub on current domain, or it's an old API, assign a new one
639-
if (!hasHubOnCarrier(activeDomain) || getHubFromCarrier(activeDomain).isOlderThan(API_VERSION)) {
640-
const registryHubTopStack = getHubFromCarrier(registry).getStackTop();
641-
setHubOnCarrier(activeDomain, new Hub(registryHubTopStack.client, Scope.clone(registryHubTopStack.scope)));
642-
}
643-
644-
// Return hub that lives on a domain
645-
return getHubFromCarrier(activeDomain);
646-
} catch (_Oo) {
647-
// Return hub that lives on a global object
648-
return getHubFromCarrier(registry);
649-
}
650-
}
651-
652607
/**
653608
* This will tell whether a carrier has a hub on it or not
654609
* @param carrier object

packages/nextjs/src/server/index.ts

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
import type { Carrier } from '@sentry/core';
2-
import { getHubFromCarrier, getMainCarrier, hasTracingEnabled } from '@sentry/core';
1+
import { hasTracingEnabled } from '@sentry/core';
32
import { RewriteFrames } from '@sentry/integrations';
43
import type { NodeOptions } from '@sentry/node';
54
import { configureScope, getCurrentHub, init as nodeInit, Integrations } from '@sentry/node';
65
import type { EventProcessor } from '@sentry/types';
76
import type { IntegrationWithExclusionOption } from '@sentry/utils';
87
import { addOrUpdateIntegration, escapeStringForRegex, logger } from '@sentry/utils';
9-
import * as domainModule from 'domain';
108
import * as path from 'path';
119

1210
import { devErrorSymbolicationEventProcessor } from '../common/devErrorSymbolicationEventProcessor';
@@ -55,8 +53,6 @@ const globalWithInjectedValues = global as typeof global & {
5553
__rewriteFramesDistDir__: string;
5654
};
5755

58-
const domain = domainModule as typeof domainModule & { active: (domainModule.Domain & Carrier) | null };
59-
6056
// TODO (v8): Remove this
6157
/**
6258
* @deprecated This constant will be removed in the next major update.
@@ -87,16 +83,6 @@ export function init(options: NodeOptions): void {
8783
// Right now we only capture frontend sessions for Next.js
8884
options.autoSessionTracking = false;
8985

90-
// In an ideal world, this init function would be called before any requests are handled. That way, every domain we
91-
// use to wrap a request would inherit its scope and client from the global hub. In practice, however, handling the
92-
// first request is what causes us to initialize the SDK, as the init code is injected into `_app` and all API route
93-
// handlers, and those are only accessed in the course of handling a request. As a result, we're already in a domain
94-
// when `init` is called. In order to compensate for this and mimic the ideal world scenario, we stash the active
95-
// domain, run `init` as normal, and then restore the domain afterwards, copying over data from the main hub as if we
96-
// really were inheriting.
97-
const activeDomain = domain.active;
98-
domain.active = null;
99-
10086
nodeInit(options);
10187

10288
const filterTransactions: EventProcessor = event => {
@@ -118,20 +104,6 @@ export function init(options: NodeOptions): void {
118104
}
119105
});
120106

121-
if (activeDomain) {
122-
const globalHub = getHubFromCarrier(getMainCarrier());
123-
const domainHub = getHubFromCarrier(activeDomain);
124-
125-
// apply the changes made by `nodeInit` to the domain's hub also
126-
domainHub.bindClient(globalHub.getClient());
127-
domainHub.getScope()?.update(globalHub.getScope());
128-
// `scope.update()` doesn’t copy over event processors, so we have to add it manually
129-
domainHub.getScope()?.addEventProcessor(filterTransactions);
130-
131-
// restore the domain hub as the current one
132-
domain.active = activeDomain;
133-
}
134-
135107
__DEBUG_BUILD__ && logger.log('SDK successfully initialized');
136108
}
137109

packages/nextjs/src/server/utils/wrapperUtils.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { captureException, getActiveTransaction, getCurrentHub, startTransaction } from '@sentry/core';
1+
import { captureException, getActiveTransaction, runWithAsyncContext, startTransaction } from '@sentry/core';
22
import type { Transaction } from '@sentry/types';
33
import { baggageHeaderToDynamicSamplingContext, extractTraceparentData } from '@sentry/utils';
4-
import * as domain from 'domain';
54
import type { IncomingMessage, ServerResponse } from 'http';
65

76
import { platformSupportsStreaming } from './platformSupportsStreaming';
@@ -75,7 +74,7 @@ export function withTracedServerSideDataFetcher<F extends (...args: any[]) => Pr
7574
},
7675
): (...params: Parameters<F>) => Promise<ReturnType<F>> {
7776
return async function (this: unknown, ...args: Parameters<F>): Promise<ReturnType<F>> {
78-
return domain.create().bind(async () => {
77+
return runWithAsyncContext(async hub => {
7978
let requestTransaction: Transaction | undefined = getTransactionFromRequest(req);
8079
let dataFetcherSpan;
8180

@@ -134,7 +133,7 @@ export function withTracedServerSideDataFetcher<F extends (...args: any[]) => Pr
134133
});
135134
}
136135

137-
const currentScope = getCurrentHub().getScope();
136+
const currentScope = hub.getScope();
138137
if (currentScope) {
139138
currentScope.setSpan(dataFetcherSpan);
140139
currentScope.setSDKProcessingMetadata({ request: req });
@@ -154,7 +153,7 @@ export function withTracedServerSideDataFetcher<F extends (...args: any[]) => Pr
154153
await flushQueue();
155154
}
156155
}
157-
})();
156+
});
158157
};
159158
}
160159

0 commit comments

Comments
 (0)