mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-17 04:17:11 +00:00
fix(cursor): close ReadableStream controller on abort to prevent consumer hangs
When abort fires after streaming begins, onAbort closed HTTP/2 handles but never closed the ReadableStream controller. Consumers waiting on reader.read() could hang indefinitely since end/error handlers were gated by streamClosed flag. Hoist controller reference to outer scope so abort handler can close it.
This commit is contained in:
@@ -416,9 +416,18 @@ export class CursorExecutor {
|
|||||||
|
|
||||||
// Register abort before response headers arrive so cancellation works at all stages
|
// Register abort before response headers arrive so cancellation works at all stages
|
||||||
let streamClosed = false;
|
let streamClosed = false;
|
||||||
|
let streamController: ReadableStreamDefaultController<Uint8Array> | null = null;
|
||||||
if (signal) {
|
if (signal) {
|
||||||
const onAbort = () => {
|
const onAbort = () => {
|
||||||
streamClosed = true;
|
streamClosed = true;
|
||||||
|
// Close the ReadableStream controller so consumers don't hang on reader.read()
|
||||||
|
if (streamController) {
|
||||||
|
try {
|
||||||
|
streamController.close();
|
||||||
|
} catch {
|
||||||
|
/* already closed */
|
||||||
|
}
|
||||||
|
}
|
||||||
req.close();
|
req.close();
|
||||||
client.close();
|
client.close();
|
||||||
};
|
};
|
||||||
@@ -471,6 +480,8 @@ export class CursorExecutor {
|
|||||||
|
|
||||||
const readable = new ReadableStream<Uint8Array>({
|
const readable = new ReadableStream<Uint8Array>({
|
||||||
start(controller) {
|
start(controller) {
|
||||||
|
streamController = controller;
|
||||||
|
|
||||||
const emitSSE = (data: string) => {
|
const emitSSE = (data: string) => {
|
||||||
if (streamClosed) return;
|
if (streamClosed) return;
|
||||||
controller.enqueue(enc.encode(`data: ${data}\n\n`));
|
controller.enqueue(enc.encode(`data: ${data}\n\n`));
|
||||||
|
|||||||
Reference in New Issue
Block a user