Skip to content

Commit f088bfb

Browse files
committed
Keep the safe() span-builder helper instead of inlining try/catch
1 parent 82ab272 commit f088bfb

1 file changed

Lines changed: 30 additions & 33 deletions

File tree

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

packages/server-utils/src/integrations/tracing-channel/aws-sdk/index.ts

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ interface AwsV3Command {
4444
constructor?: { name?: string };
4545
}
4646

47+
/** Runs a span-building callback so a throw inside it can never break the user's aws-sdk call. */
48+
function safe<T>(fn: () => T): T | undefined {
49+
try {
50+
return fn();
51+
} catch (error) {
52+
DEBUG_BUILD && debug.warn('[orchestrion:aws-sdk] error building span', error);
53+
return undefined;
54+
}
55+
}
56+
4757
// `metadata` is smithy's `ResponseMetadata`, read off the untyped channel result/error (`any` for the
4858
// same reason as `CommandInput`, see types.ts).
4959
function setMetadataAttributes(span: Span, metadata: Record<string, any> | undefined): void {
@@ -73,10 +83,8 @@ const _awsChannelIntegration = (() => {
7383
return;
7484
}
7585

76-
// Everything in here (and in `deferSpanEnd` below) runs inside the tracingChannel machinery
77-
// wrapping the user's `send` call, so a throw must never escape: it would break the AWS call.
78-
const getSpan = (data: AwsSendChannelContext): Span | undefined => {
79-
try {
86+
const getSpan = (data: AwsSendChannelContext): Span | undefined =>
87+
safe(() => {
8088
const command = data.arguments[0] as AwsV3Command | undefined;
8189
const commandName = command?.constructor?.name;
8290
if (!command || !commandName) {
@@ -125,7 +133,7 @@ const _awsChannelIntegration = (() => {
125133
// so `cloud.region` cannot be lost when `send` settles first (e.g. an early failure).
126134
//
127135
// The provider call is guarded separately: the span is already started, so a synchronous
128-
// throw bubbling into the enclosing catch would discard it without ending it (a leaked
136+
// throw bubbling into the enclosing `safe` would discard it without ending it (a leaked
129137
// open span).
130138
let regionResult: string | Promise<string> | undefined;
131139
try {
@@ -153,20 +161,11 @@ const _awsChannelIntegration = (() => {
153161
data._sentryRegion = regionHolder;
154162

155163
// Inject trace-propagation headers into outgoing messages (SQS/SNS/Lambda). Runs before
156-
// `send` proceeds, so the mutated `commandInput` is used to build the request. Guarded
157-
// separately so a throw can't discard the already-started span via the outer catch.
158-
try {
159-
servicesExtensions.requestPostSpanHook(normalizedRequest, span);
160-
} catch (error) {
161-
DEBUG_BUILD && debug.warn('[orchestrion:aws-sdk] error in request post-span hook', error);
162-
}
164+
// `send` proceeds, so the mutated `commandInput` is used to build the request.
165+
safe(() => servicesExtensions.requestPostSpanHook(normalizedRequest, span));
163166

164167
return span;
165-
} catch (error) {
166-
DEBUG_BUILD && debug.warn('[orchestrion:aws-sdk] error building span', error);
167-
return undefined;
168-
}
169-
};
168+
});
170169

171170
const opts: TracingChannelLifeCycleOptions<AwsSendChannelContext> = {
172171
deferSpanEnd({ span, data, end }) {
@@ -179,9 +178,8 @@ const _awsChannelIntegration = (() => {
179178
const failed = 'error' in data;
180179

181180
// The channel `result`/`error` are untyped; the `$metadata` casts below name smithy's
182-
// `ResponseMetadata` shape (`any`-valued, see `setMetadataAttributes`). Guarded so an
183-
// enrichment throw can't escape into the user's `send` (see `getSpan`).
184-
try {
181+
// `ResponseMetadata` shape (`any`-valued, see `setMetadataAttributes`).
182+
safe(() => {
185183
if (failed) {
186184
const err = data.error as
187185
| { $metadata?: Record<string, any>; RequestId?: string; extendedRequestId?: string }
@@ -195,20 +193,19 @@ const _awsChannelIntegration = (() => {
195193
httpStatusCode: errMetadata?.httpStatusCode,
196194
extendedRequestId: err?.extendedRequestId ?? errMetadata?.extendedRequestId,
197195
});
198-
} else {
199-
const output = data.result as { $metadata?: Record<string, any> } | undefined;
200-
setMetadataAttributes(span, output?.$metadata);
201-
202-
const normalizedResponse: NormalizedResponse = {
203-
data: output,
204-
request: normalizedRequest,
205-
requestId: output?.$metadata?.requestId,
206-
};
207-
servicesExtensions.responseHook(normalizedResponse, span);
196+
return;
208197
}
209-
} catch (error) {
210-
DEBUG_BUILD && debug.warn('[orchestrion:aws-sdk] error enriching span', error);
211-
}
198+
199+
const output = data.result as { $metadata?: Record<string, any> } | undefined;
200+
setMetadataAttributes(span, output?.$metadata);
201+
202+
const normalizedResponse: NormalizedResponse = {
203+
data: output,
204+
request: normalizedRequest,
205+
requestId: output?.$metadata?.requestId,
206+
};
207+
servicesExtensions.responseHook(normalizedResponse, span);
208+
});
212209

213210
// Streaming responses end the span when their wrapped stream is consumed (see
214211
// bedrock-runtime); the helper must not end it on `send` settling. Errors always end here.

0 commit comments

Comments
 (0)