fix(web): SSE 重连 401/404 fail-fast,单帧解析容错(R-7)
TaskRunHttpError 携带 status;非法 JSON 帧跳过并保留 seq。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -119,7 +119,12 @@ function parseFrame(frame: string): { event: StreamEvent | null; seq?: number }
|
||||
// SSE comment / heartbeat frames (": ...") have no data — ignore.
|
||||
if (!dataLine) return { event: null, seq };
|
||||
|
||||
return { event: JSON.parse(dataLine) as StreamEvent, seq };
|
||||
try {
|
||||
return { event: JSON.parse(dataLine) as StreamEvent, seq };
|
||||
} catch (err) {
|
||||
console.warn('[sse] 忽略无法解析的帧:', dataLine.slice(0, 200), err);
|
||||
return { event: null, seq };
|
||||
}
|
||||
}
|
||||
|
||||
export function parseSSEChunk(
|
||||
|
||||
+17
-1
@@ -37,6 +37,19 @@ export function sleepMs(ms: number): Promise<void> {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
export class TaskRunHttpError extends Error {
|
||||
status: number;
|
||||
constructor(status: number) {
|
||||
super(`subscribe task run failed: HTTP ${status}`);
|
||||
this.name = 'TaskRunHttpError';
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
|
||||
function isNonRetryableStatus(status: number): boolean {
|
||||
return status === 401 || status === 404;
|
||||
}
|
||||
|
||||
/** 单次 SSE 读取;意外 EOF 时返回 { terminal:false, lastSeq } 供上层重连。 */
|
||||
export async function readTaskRunSSEOnce(
|
||||
runId: string,
|
||||
@@ -51,7 +64,7 @@ export async function readTaskRunSSEOnce(
|
||||
signal,
|
||||
});
|
||||
if (!resp.ok || !resp.body) {
|
||||
throw new Error(`subscribe task run failed: HTTP ${resp.status}`);
|
||||
throw new TaskRunHttpError(resp.status);
|
||||
}
|
||||
const reader = resp.body.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
@@ -113,6 +126,9 @@ export async function subscribeTaskRunEvents(
|
||||
// 意外 EOF:未见到 done/error,按 after_seq 重连
|
||||
} catch (err) {
|
||||
if (signal?.aborted) return;
|
||||
if (err instanceof TaskRunHttpError && isNonRetryableStatus(err.status)) {
|
||||
throw err;
|
||||
}
|
||||
if (attempt >= maxReconnects) throw err;
|
||||
}
|
||||
if (attempt >= maxReconnects) {
|
||||
|
||||
Reference in New Issue
Block a user