fix: handle SSE controller errors gracefully

- Add isActive checks before writing to SSE controller
- Wrap controller operations in try/catch to prevent 'already closed' errors
- Fix race condition when client disconnects during SSE streaming
This commit is contained in:
2026-03-06 22:40:57 +01:00
parent f0a967515b
commit 9141edfaa9
2 changed files with 32 additions and 13 deletions

View File

@@ -33,26 +33,38 @@ export async function GET(
}, },
}); });
if (response.ok) { if (response.ok && isActive) {
const data = await response.json(); const data = await response.json();
const dataStr = JSON.stringify(data); const dataStr = JSON.stringify(data);
// Only send if data changed // Only send if data changed
if (dataStr !== lastData) { if (dataStr !== lastData && isActive) {
lastData = dataStr; lastData = dataStr;
controller.enqueue( try {
new TextEncoder().encode(`data: ${dataStr}\n\n`) controller.enqueue(
); new TextEncoder().encode(`data: ${dataStr}\n\n`)
);
} catch (err) {
// Controller closed, ignore
isActive = false;
return;
}
// Stop polling if job is complete // Stop polling if job is complete
if (data.status === "success" || data.status === "failed" || data.status === "cancelled") { if (data.status === "success" || data.status === "failed" || data.status === "cancelled") {
isActive = false; isActive = false;
controller.close(); try {
controller.close();
} catch (err) {
// Already closed, ignore
}
} }
} }
} }
} catch (error) { } catch (error) {
console.error("SSE fetch error:", error); if (isActive) {
console.error("SSE fetch error:", error);
}
} }
}; };

View File

@@ -28,20 +28,27 @@ export async function GET(request: NextRequest) {
}, },
}); });
if (response.ok) { if (response.ok && isActive) {
const data = await response.json(); const data = await response.json();
const dataStr = JSON.stringify(data); const dataStr = JSON.stringify(data);
// Send if data changed // Send if data changed
if (dataStr !== lastData) { if (dataStr !== lastData && isActive) {
lastData = dataStr; lastData = dataStr;
controller.enqueue( try {
new TextEncoder().encode(`data: ${dataStr}\n\n`) controller.enqueue(
); new TextEncoder().encode(`data: ${dataStr}\n\n`)
);
} catch (err) {
// Controller closed, ignore
isActive = false;
}
} }
} }
} catch (error) { } catch (error) {
console.error("SSE fetch error:", error); if (isActive) {
console.error("SSE fetch error:", error);
}
} }
}; };