Skip to content

Commit 334851d

Browse files
committed
fix: bugbot comments
1 parent 606a192 commit 334851d

2 files changed

Lines changed: 107 additions & 7 deletions

File tree

‎packages/deno/src/wrap-deno-request-handler.ts‎

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,15 @@ function captureServeError(e: unknown): void {
4545
});
4646
}
4747

48+
// A user hook that throws must not fail the request or leave the span open.
49+
function callHook(name: string, hook: () => void): void {
50+
try {
51+
hook();
52+
} catch (e) {
53+
debug.warn(`Error in the Deno.serve ${name} hook.`, e);
54+
}
55+
}
56+
4857
function shouldCreateSpan(
4958
client: Client,
5059
integration: DenoServeIntegrationOptions | undefined,
@@ -178,7 +187,10 @@ export const wrapDenoRequestHandler = <Addr extends Deno.Addr = Deno.Addr>(
178187
}
179188

180189
return startSpanManual({ name, attributes }, async span => {
181-
integration?.onSpanCreated?.(span, request);
190+
const { onSpanCreated, onSpanEnd } = integration ?? {};
191+
if (onSpanCreated) {
192+
callHook('onSpanCreated', () => onSpanCreated(span, request));
193+
}
182194
let res: Response;
183195

184196
try {
@@ -196,8 +208,11 @@ export const wrapDenoRequestHandler = <Addr extends Deno.Addr = Deno.Addr>(
196208
throw e;
197209
}
198210

199-
const onSpanEnd = integration?.onSpanEnd;
200-
return streamResponse(span, res, onSpanEnd && (() => onSpanEnd(span, request, res)));
211+
return streamResponse(
212+
span,
213+
res,
214+
onSpanEnd && (() => callHook('onSpanEnd', () => onSpanEnd(span, request, res))),
215+
);
201216
});
202217
},
203218
);

‎packages/deno/test/deno-serve.test.ts‎

Lines changed: 89 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -997,7 +997,7 @@ Deno.test('Deno.serve should not create spans for requests that ignoreIncomingRe
997997
const errorEvents: ErrorEvent[] = [];
998998
const urlPaths: string[] = [];
999999

1000-
init({
1000+
const client = init({
10011001
dsn: 'https://username@domain/123',
10021002
tracesSampleRate: 1,
10031003
traceLifecycle: 'static',
@@ -1031,7 +1031,7 @@ Deno.test('Deno.serve should not create spans for requests that ignoreIncomingRe
10311031
await (await fetch(`${server.url}/health/fail`)).text();
10321032
await (await fetch(`${server.url}/users`)).text();
10331033
await server.close();
1034-
await delay(100);
1034+
await client.flush();
10351035

10361036
assertEquals(urlPaths, ['/health?ok=1', '/health/fail', '/users']);
10371037
assertEquals(
@@ -1102,7 +1102,7 @@ Deno.test('Deno.serve should not create spans when spans is false, but still cap
11021102
const transactionEvents: TransactionEvent[] = [];
11031103
const errorEvents: ErrorEvent[] = [];
11041104

1105-
init({
1105+
const client = init({
11061106
dsn: 'https://username@domain/123',
11071107
tracesSampleRate: 1,
11081108
traceLifecycle: 'static',
@@ -1130,7 +1130,7 @@ Deno.test('Deno.serve should not create spans when spans is false, but still cap
11301130
await (await fetch(`${server.url}/ok`)).text();
11311131
await (await fetch(`${server.url}/error`, { method: 'POST', body: 'payload' })).text();
11321132
await server.close();
1133-
await delay(100);
1133+
await client.flush();
11341134

11351135
assertEquals(transactionEvents.length, 0);
11361136
assertEquals(errorEvents.length, 1);
@@ -1245,3 +1245,88 @@ Deno.test('Deno.serve should call onSpanEnd when a streamed response finishes',
12451245
assertEquals(transactionEvents.length, 1);
12461246
assertEquals(transactionEvents[0]?.contexts?.trace?.data?.['test.ended'], true);
12471247
});
1248+
1249+
Deno.test('Deno.serve should still respond and end the span when onSpanCreated throws', async () => {
1250+
resetGlobals();
1251+
const transactionEvents: TransactionEvent[] = [];
1252+
1253+
init({
1254+
dsn: 'https://username@domain/123',
1255+
tracesSampleRate: 1,
1256+
traceLifecycle: 'static',
1257+
integrations: integrations => [
1258+
...integrations.filter(integration => integration.name !== 'DenoServe'),
1259+
denoServeIntegration({
1260+
onSpanCreated: () => {
1261+
throw new Error('onSpanCreated failed');
1262+
},
1263+
}),
1264+
],
1265+
beforeSendTransaction: (event: TransactionEvent) => {
1266+
transactionEvents.push(event);
1267+
return null;
1268+
},
1269+
}) as DenoClient;
1270+
1271+
const server = await serveForTest(() => new Response('OK'));
1272+
const response = await fetch(`${server.url}/created`);
1273+
assertEquals(response.status, 200);
1274+
assertEquals(await response.text(), 'OK');
1275+
await server.close();
1276+
1277+
assertEquals(
1278+
transactionEvents.map(event => event.transaction),
1279+
['GET /created'],
1280+
);
1281+
});
1282+
1283+
for (const [label, makeResponse] of [
1284+
['a response', () => new Response('OK')],
1285+
[
1286+
'a streamed response',
1287+
() =>
1288+
new Response(
1289+
new ReadableStream({
1290+
start(controller) {
1291+
controller.enqueue(new TextEncoder().encode('OK'));
1292+
controller.close();
1293+
},
1294+
}),
1295+
{ headers: { 'content-type': 'text/event-stream' } },
1296+
),
1297+
],
1298+
] as const) {
1299+
Deno.test(`Deno.serve should still respond and end the span when onSpanEnd throws for ${label}`, async () => {
1300+
resetGlobals();
1301+
const transactionEvents: TransactionEvent[] = [];
1302+
1303+
init({
1304+
dsn: 'https://username@domain/123',
1305+
tracesSampleRate: 1,
1306+
traceLifecycle: 'static',
1307+
integrations: integrations => [
1308+
...integrations.filter(integration => integration.name !== 'DenoServe'),
1309+
denoServeIntegration({
1310+
onSpanEnd: () => {
1311+
throw new Error('onSpanEnd failed');
1312+
},
1313+
}),
1314+
],
1315+
beforeSendTransaction: (event: TransactionEvent) => {
1316+
transactionEvents.push(event);
1317+
return null;
1318+
},
1319+
}) as DenoClient;
1320+
1321+
const server = await serveForTest(makeResponse);
1322+
const response = await fetch(`${server.url}/ended`);
1323+
assertEquals(response.status, 200);
1324+
assertEquals(await response.text(), 'OK');
1325+
await server.close();
1326+
1327+
assertEquals(
1328+
transactionEvents.map(event => event.transaction),
1329+
['GET /ended'],
1330+
);
1331+
});
1332+
}

0 commit comments

Comments
 (0)