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:
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user