From d21c77e4f4168f90da187cb78e7a755bd217c8c9 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Wed, 5 Apr 2023 11:26:00 +0200 Subject: [PATCH 1/4] Add async context abstraction --- packages/core/src/hub.ts | 40 ++++++++++++++++++++++++++++++++++++++ packages/core/src/index.ts | 2 +- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/packages/core/src/hub.ts b/packages/core/src/hub.ts index 6f109dfe1ce4..3ffa18db5161 100644 --- a/packages/core/src/hub.ts +++ b/packages/core/src/hub.ts @@ -50,6 +50,14 @@ export const API_VERSION = 4; */ const DEFAULT_BREADCRUMBS = 100; +/** + * Strategy used to track async context. + */ +export interface AsyncContextStrategy { + getCurrentHub: () => Hub | undefined; + runWithHub(callback: (hub: Hub) => T): T; +} + /** * A layer in the process stack. * @hidden @@ -66,6 +74,7 @@ export interface Layer { export interface Carrier { __SENTRY__?: { hub?: Hub; + asyncContextStrategy?: AsyncContextStrategy; /** * Extra Hub properties injected by various SDKs */ @@ -519,6 +528,14 @@ export function getCurrentHub(): Hub { // Get main carrier (global for every environment) const registry = getMainCarrier(); + if (registry.__SENTRY__ && registry.__SENTRY__.asyncContextStrategy) { + const hub = registry.__SENTRY__.asyncContextStrategy.getCurrentHub(); + + if (hub) { + return hub; + } + } + // If there's no hub, or its an old API, assign a new one if (!hasHubOnCarrier(registry) || getHubFromCarrier(registry).isOlderThan(API_VERSION)) { setHubOnCarrier(registry, new Hub()); @@ -532,6 +549,29 @@ export function getCurrentHub(): Hub { return getHubFromCarrier(registry); } +/** + * Sets the global async context strategy + */ +export function setAsyncContextStrategy(strategy: AsyncContextStrategy): void { + // Get main carrier (global for every environment) + const registry = getMainCarrier(); + registry.__SENTRY__ = registry.__SENTRY__ || {}; + registry.__SENTRY__.asyncContextStrategy = strategy; +} + +/** + * Runs the given callback function with the global async context strategy + */ +export function runWithHub(callback: (hub: Hub) => T): T { + const registry = getMainCarrier(); + + if (registry.__SENTRY__ && registry.__SENTRY__.asyncContextStrategy) { + return registry.__SENTRY__.asyncContextStrategy.runWithHub(callback); + } + + return callback(getCurrentHub()); +} + /** * Try to read the hub from an active domain, and fallback to the registry if one doesn't exist * @returns discovered hub diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index e5ee3c623d76..c6e2d7bfa616 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,5 +1,5 @@ export type { ClientClass } from './sdk'; -export type { Carrier, Layer } from './hub'; +export type { AsyncContextStrategy, Carrier, Layer } from './hub'; export type { OfflineStore, OfflineTransportOptions } from './transports/offline'; export * from './tracing'; From 7766272c561d0ee74298e5ad89d913744a502882 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Wed, 5 Apr 2023 12:12:12 +0200 Subject: [PATCH 2/4] Better types and names --- packages/core/src/hub.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/core/src/hub.ts b/packages/core/src/hub.ts index 3ffa18db5161..c11ce0bf1428 100644 --- a/packages/core/src/hub.ts +++ b/packages/core/src/hub.ts @@ -55,7 +55,7 @@ const DEFAULT_BREADCRUMBS = 100; */ export interface AsyncContextStrategy { getCurrentHub: () => Hub | undefined; - runWithHub(callback: (hub: Hub) => T): T; + runWithAsyncContext(callback: (hub: Hub, ...args: A[]) => T, ...args: A[]): T; } /** @@ -562,14 +562,15 @@ export function setAsyncContextStrategy(strategy: AsyncContextStrategy): void { /** * Runs the given callback function with the global async context strategy */ -export function runWithHub(callback: (hub: Hub) => T): T { +export function runWithAsyncContext(callback: (hub: Hub, ...args: A[]) => T, ...args: A[]): T { const registry = getMainCarrier(); if (registry.__SENTRY__ && registry.__SENTRY__.asyncContextStrategy) { - return registry.__SENTRY__.asyncContextStrategy.runWithHub(callback); + return registry.__SENTRY__.asyncContextStrategy.runWithAsyncContext(callback, ...args); } - return callback(getCurrentHub()); + // if there was no asyncContextStrategy, fallback to just calling the callback + return callback(getCurrentHub(), ...args); } /** From 1f92db67a0c68ad27b5a791debea5a4bcde078b0 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Wed, 5 Apr 2023 12:12:44 +0200 Subject: [PATCH 3/4] Export `runWithAsyncContext` from core --- packages/core/src/index.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index c6e2d7bfa616..46199d145a96 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -18,7 +18,15 @@ export { setUser, withScope, } from './exports'; -export { getCurrentHub, getHubFromCarrier, Hub, makeMain, getMainCarrier, setHubOnCarrier } from './hub'; +export { + getCurrentHub, + getHubFromCarrier, + Hub, + makeMain, + getMainCarrier, + setHubOnCarrier, + runWithAsyncContext, +} from './hub'; export { makeSession, closeSession, updateSession } from './session'; export { SessionFlusher } from './sessionflusher'; export { addGlobalEventProcessor, Scope } from './scope'; From 3ccf03410ea548a68acfeba59bac55f222b16e52 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Wed, 5 Apr 2023 18:32:11 +0200 Subject: [PATCH 4/4] Code review changes --- packages/core/src/hub.ts | 18 +++++++++++------- packages/core/src/index.ts | 3 ++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/core/src/hub.ts b/packages/core/src/hub.ts index c11ce0bf1428..1a2358b81555 100644 --- a/packages/core/src/hub.ts +++ b/packages/core/src/hub.ts @@ -74,7 +74,7 @@ export interface Layer { export interface Carrier { __SENTRY__?: { hub?: Hub; - asyncContextStrategy?: AsyncContextStrategy; + acs?: AsyncContextStrategy; /** * Extra Hub properties injected by various SDKs */ @@ -528,8 +528,8 @@ export function getCurrentHub(): Hub { // Get main carrier (global for every environment) const registry = getMainCarrier(); - if (registry.__SENTRY__ && registry.__SENTRY__.asyncContextStrategy) { - const hub = registry.__SENTRY__.asyncContextStrategy.getCurrentHub(); + if (registry.__SENTRY__ && registry.__SENTRY__.acs) { + const hub = registry.__SENTRY__.acs.getCurrentHub(); if (hub) { return hub; @@ -550,26 +550,30 @@ export function getCurrentHub(): Hub { } /** + * @private Private API with no semver guarantees! + * * Sets the global async context strategy */ export function setAsyncContextStrategy(strategy: AsyncContextStrategy): void { // Get main carrier (global for every environment) const registry = getMainCarrier(); registry.__SENTRY__ = registry.__SENTRY__ || {}; - registry.__SENTRY__.asyncContextStrategy = strategy; + registry.__SENTRY__.acs = strategy; } /** + * @private Private API with no semver guarantees! + * * Runs the given callback function with the global async context strategy */ export function runWithAsyncContext(callback: (hub: Hub, ...args: A[]) => T, ...args: A[]): T { const registry = getMainCarrier(); - if (registry.__SENTRY__ && registry.__SENTRY__.asyncContextStrategy) { - return registry.__SENTRY__.asyncContextStrategy.runWithAsyncContext(callback, ...args); + if (registry.__SENTRY__ && registry.__SENTRY__.acs) { + return registry.__SENTRY__.acs.runWithAsyncContext(callback, ...args); } - // if there was no asyncContextStrategy, fallback to just calling the callback + // if there was no strategy, fallback to just calling the callback return callback(getCurrentHub(), ...args); } diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 46199d145a96..ee8e624709a0 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -24,8 +24,9 @@ export { Hub, makeMain, getMainCarrier, - setHubOnCarrier, runWithAsyncContext, + setHubOnCarrier, + setAsyncContextStrategy, } from './hub'; export { makeSession, closeSession, updateSession } from './session'; export { SessionFlusher } from './sessionflusher';