Skip to content

Commit c0fdc88

Browse files
committed
feat(deno): more tests
1 parent 8949809 commit c0fdc88

File tree

2 files changed

+50
-39
lines changed

2 files changed

+50
-39
lines changed

packages/deno/src/utils/streaming.ts

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { Span } from "@sentry/core";
2+
13
export type StreamingGuess = {
24
isStreaming: boolean;
35
};
@@ -39,3 +41,49 @@ export function classifyResponseStreaming(res: Response): StreamingGuess {
3941
// Default: treat as non-streaming
4042
return { isStreaming: false };
4143
}
44+
45+
/**
46+
* Tee a stream, and end the provided span when the stream ends.
47+
* Returns the other side of the tee, which can be used to send the
48+
* response to a client.
49+
*/
50+
export async function streamResponse(span: Span, res: Response): Promise<Response> {
51+
const classification = classifyResponseStreaming(res);
52+
53+
// not streaming, just end the span and return the response
54+
if (!classification.isStreaming || !res.body) {
55+
span.end();
56+
return res;
57+
}
58+
59+
// Streaming response detected - monitor consumption to keep span alive
60+
try {
61+
// Monitor stream consumption and end span when complete
62+
const [clientStream, monitorStream] = res.body.tee();
63+
await (async () => {
64+
const reader = monitorStream.getReader();
65+
try {
66+
let done = false;
67+
while (!done) {
68+
const result = await reader.read();
69+
done = result.done;
70+
}
71+
} catch {
72+
// Stream error or cancellation - will end span in finally
73+
} finally {
74+
reader.releaseLock();
75+
span.end();
76+
}
77+
})();
78+
// Return response with client stream
79+
return new Response(clientStream, {
80+
status: res.status,
81+
statusText: res.statusText,
82+
headers: res.headers,
83+
});
84+
} catch (e) {
85+
// tee() failed - handle without streaming
86+
span.end();
87+
return res
88+
}
89+
}

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

Lines changed: 2 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
} from '@sentry/core';
1414
import { init } from './sdk';
1515
import type { DenoOptions } from './types';
16-
import { classifyResponseStreaming } from './utils/streaming';
16+
import { streamResponse } from './utils/streaming';
1717

1818
export type RequestHandlerWrapperOptions<Addr extends Deno.Addr> = {
1919
request: Request;
@@ -104,44 +104,7 @@ export const wrapDenoRequestHandler = <Addr extends Deno.Addr = Deno.Addr>(
104104
throw e;
105105
}
106106

107-
// Classify response to detect actual streaming
108-
const classification = classifyResponseStreaming(res);
109-
if (classification.isStreaming && res.body) {
110-
// Streaming response detected - monitor consumption to keep span alive
111-
try {
112-
const [clientStream, monitorStream] = res.body.tee();
113-
114-
// Monitor stream consumption and end span when complete
115-
await (async () => {
116-
const reader = monitorStream.getReader();
117-
try {
118-
let done = false;
119-
while (!done) {
120-
const result = await reader.read();
121-
done = result.done;
122-
}
123-
} catch {
124-
// Stream error or cancellation - will end span in finally
125-
} finally {
126-
reader.releaseLock();
127-
span.end();
128-
}
129-
})();
130-
131-
// Return response with client stream
132-
return new Response(clientStream, {
133-
status: res.status,
134-
statusText: res.statusText,
135-
headers: res.headers,
136-
});
137-
} catch (e) {
138-
// tee() failed - fall through to non-streaming handling
139-
}
140-
}
141-
142-
// Non-streaming response - end span immediately and return original
143-
span.end();
144-
return res;
107+
return streamResponse(span, res);
145108
});
146109
},
147110
);

0 commit comments

Comments
 (0)