fix(workbench): share sync reads and retry failed invalidations

This commit is contained in:
2026-10-08 15:41:50 +08:00
parent 64ef058e0d
commit 7c6d06cb43
8 changed files with 274 additions and 74 deletions
@@ -82,6 +82,7 @@ export async function consumeWorkbenchEvents(input: {
after: number;
getAccessToken?: AccessTokenProvider;
onEvents: (events: WorkbenchEvent[]) => void;
onOpen?: () => void;
onReset: () => Promise<void>;
signal: AbortSignal;
}): Promise<"closed" | "reset"> {
@@ -98,30 +99,36 @@ export async function consumeWorkbenchEvents(input: {
throw new Error(getServerError(payload, response.status, "工作台事件连接"));
}
const reader = response.body.getReader();
input.onOpen?.();
const decoder = new TextDecoder();
let buffer = "";
while (!input.signal.aborted) {
const { value, done } = await reader.read();
buffer += decoder.decode(value, { stream: !done });
if (buffer.length > 1_048_576) throw new Error("工作台事件帧超过大小限制");
const events: WorkbenchEvent[] = [];
let boundary = buffer.search(/\r?\n\r?\n/);
while (boundary >= 0) {
const separator = buffer.slice(boundary).match(/^\r?\n\r?\n/)?.[0] ?? "\n\n";
const block = buffer.slice(0, boundary);
buffer = buffer.slice(boundary + separator.length);
const lines = block.split(/\r?\n/);
const eventName = lines.find((line) => line.startsWith("event:"))?.slice(6).trim();
const data = lines.filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trim()).join("\n");
if (eventName === "reset_required") {
await input.onReset();
return "reset";
try {
while (!input.signal.aborted) {
const { value, done } = await reader.read();
buffer += decoder.decode(value, { stream: !done });
if (buffer.length > 1_048_576) throw new Error("工作台事件帧超过大小限制");
const events: WorkbenchEvent[] = [];
let boundary = buffer.search(/\r?\n\r?\n/);
while (boundary >= 0) {
const separator = buffer.slice(boundary).match(/^\r?\n\r?\n/)?.[0] ?? "\n\n";
const block = buffer.slice(0, boundary);
buffer = buffer.slice(boundary + separator.length);
const lines = block.split(/\r?\n/);
const eventName = lines.find((line) => line.startsWith("event:"))?.slice(6).trim();
const data = lines.filter((line) => line.startsWith("data:")).map((line) => line.slice(5).trim()).join("\n");
if (eventName === "reset_required") {
await input.onReset();
return "reset";
}
if (eventName === "workbench_event" && data) events.push(eventSchema.parse(JSON.parse(data)));
boundary = buffer.search(/\r?\n\r?\n/);
}
if (eventName === "workbench_event" && data) events.push(eventSchema.parse(JSON.parse(data)));
boundary = buffer.search(/\r?\n\r?\n/);
if (events.length > 0) input.onEvents(events);
if (done) return "closed";
}
if (events.length > 0) input.onEvents(events);
if (done) return "closed";
return "closed";
} finally {
await reader.cancel().catch(() => undefined);
reader.releaseLock();
}
return "closed";
}