mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 12:15:57 +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
|
||||
let streamClosed = false;
|
||||
let streamController: ReadableStreamDefaultController<Uint8Array> | null = null;
|
||||
if (signal) {
|
||||
const onAbort = () => {
|
||||
streamClosed = true;
|
||||
// Close the ReadableStream controller so consumers don't hang on reader.read()
|
||||
if (streamController) {
|
||||
try {
|
||||
streamController.close();
|
||||
} catch {
|
||||
/* already closed */
|
||||
}
|
||||
}
|
||||
req.close();
|
||||
client.close();
|
||||
};
|
||||
@@ -471,6 +480,8 @@ export class CursorExecutor {
|
||||
|
||||
const readable = new ReadableStream<Uint8Array>({
|
||||
start(controller) {
|
||||
streamController = controller;
|
||||
|
||||
const emitSSE = (data: string) => {
|
||||
if (streamClosed) return;
|
||||
controller.enqueue(enc.encode(`data: ${data}\n\n`));
|
||||
|
||||
Reference in New Issue
Block a user