fix: stabilize worker console refresh
This commit is contained in:
parent
c3fed59109
commit
a1083908b6
|
|
@ -57,7 +57,7 @@ Deno.test("Worker Console page is routed by runtime_id and worker_id through bac
|
||||||
);
|
);
|
||||||
assert(
|
assert(
|
||||||
consolePage.includes(
|
consolePage.includes(
|
||||||
"/api/runtimes/${encodeURIComponent(runtimeId)}/workers/${encodeURIComponent(workerId)}",
|
"/api/runtimes/${encodeURIComponent(target.runtimeId)}/workers/${encodeURIComponent(target.workerId)}",
|
||||||
),
|
),
|
||||||
"Worker detail should use the backend Worker detail API",
|
"Worker detail should use the backend Worker detail API",
|
||||||
);
|
);
|
||||||
|
|
@ -75,4 +75,17 @@ Deno.test("Worker Console page is routed by runtime_id and worker_id through bac
|
||||||
consolePage.includes("Streaming observation is not available"),
|
consolePage.includes("Streaming observation is not available"),
|
||||||
"Console should show an explicit non-streaming degradation path",
|
"Console should show an explicit non-streaming degradation path",
|
||||||
);
|
);
|
||||||
|
assert(
|
||||||
|
consolePage.includes("function advanceReloadToken()") &&
|
||||||
|
consolePage.includes("nextReloadToken += 1") &&
|
||||||
|
!consolePage.includes("reloadToken += 1"),
|
||||||
|
"reload token advancement should not synchronously read and write the rune state",
|
||||||
|
);
|
||||||
|
assert(
|
||||||
|
consolePage.includes(
|
||||||
|
"advanceReloadToken();\n void loadConsoleData(target);",
|
||||||
|
) &&
|
||||||
|
!consolePage.includes("void refreshConsole();\n });\n\n $effect"),
|
||||||
|
"target-change effect should load data without depending on manual refresh state reads",
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,15 @@
|
||||||
let streamState = $state<'connecting' | 'open' | 'unsupported' | 'closed' | 'error'>('connecting');
|
let streamState = $state<'connecting' | 'open' | 'unsupported' | 'closed' | 'error'>('connecting');
|
||||||
let streamDiagnostics = $state<Diagnostic[]>([]);
|
let streamDiagnostics = $state<Diagnostic[]>([]);
|
||||||
let observedEvents = $state<Array<{ cursor: string; event: ClientWorkerEventWsFrame & { kind: 'event' } }>>([]);
|
let observedEvents = $state<Array<{ cursor: string; event: ClientWorkerEventWsFrame & { kind: 'event' } }>>([]);
|
||||||
let reloadToken = 0;
|
let nextReloadToken = 0;
|
||||||
|
let reloadToken = $state(0);
|
||||||
|
|
||||||
|
type ConsoleTarget = {
|
||||||
|
runtimeId: string;
|
||||||
|
workerId: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const consoleTarget = $derived({ runtimeId, workerId });
|
||||||
|
|
||||||
const projection = $derived(
|
const projection = $derived(
|
||||||
projectConsole(
|
projectConsole(
|
||||||
|
|
@ -101,11 +109,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadWorker() {
|
async function loadWorker(target: ConsoleTarget) {
|
||||||
workerError = null;
|
workerError = null;
|
||||||
try {
|
try {
|
||||||
worker = await getJson<Worker>(
|
worker = await getJson<Worker>(
|
||||||
`/api/runtimes/${encodeURIComponent(runtimeId)}/workers/${encodeURIComponent(workerId)}`
|
`/api/runtimes/${encodeURIComponent(target.runtimeId)}/workers/${encodeURIComponent(target.workerId)}`
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
workerError = error instanceof Error ? error.message : String(error);
|
workerError = error instanceof Error ? error.message : String(error);
|
||||||
|
|
@ -113,11 +121,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function loadTranscript() {
|
async function loadTranscript(target: ConsoleTarget) {
|
||||||
transcriptError = null;
|
transcriptError = null;
|
||||||
try {
|
try {
|
||||||
transcript = await getJson<WorkerTranscriptProjection>(
|
transcript = await getJson<WorkerTranscriptProjection>(
|
||||||
`/api/runtimes/${encodeURIComponent(runtimeId)}/workers/${encodeURIComponent(workerId)}/transcript?limit=200`
|
`/api/runtimes/${encodeURIComponent(target.runtimeId)}/workers/${encodeURIComponent(target.workerId)}/transcript?limit=200`
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
transcriptError = error instanceof Error ? error.message : String(error);
|
transcriptError = error instanceof Error ? error.message : String(error);
|
||||||
|
|
@ -125,9 +133,19 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function loadConsoleData(target: ConsoleTarget) {
|
||||||
|
await Promise.all([loadWorker(target), loadTranscript(target)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function advanceReloadToken(): number {
|
||||||
|
nextReloadToken += 1;
|
||||||
|
reloadToken = nextReloadToken;
|
||||||
|
return nextReloadToken;
|
||||||
|
}
|
||||||
|
|
||||||
async function refreshConsole() {
|
async function refreshConsole() {
|
||||||
reloadToken += 1;
|
advanceReloadToken();
|
||||||
await Promise.all([loadWorker(), loadTranscript()]);
|
await loadConsoleData(consoleTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function sendMessage(event: SubmitEvent) {
|
async function sendMessage(event: SubmitEvent) {
|
||||||
|
|
@ -149,7 +167,7 @@
|
||||||
} else {
|
} else {
|
||||||
sendError = diagnosticsToText(result.diagnostics) || `Input was ${result.state}.`;
|
sendError = diagnosticsToText(result.diagnostics) || `Input was ${result.state}.`;
|
||||||
}
|
}
|
||||||
await loadTranscript();
|
await loadTranscript(consoleTarget);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
sendError = error instanceof Error ? error.message : String(error);
|
sendError = error instanceof Error ? error.message : String(error);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
@ -157,12 +175,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function connectObservation(target: Worker | null, token: number) {
|
function connectObservation(targetWorker: Worker | null, token: number, target: ConsoleTarget) {
|
||||||
if (!target) {
|
if (!targetWorker) {
|
||||||
streamState = 'closed';
|
streamState = 'closed';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!target.capabilities.can_stream_events) {
|
if (!targetWorker.capabilities.can_stream_events) {
|
||||||
streamState = 'unsupported';
|
streamState = 'unsupported';
|
||||||
streamDiagnostics = [
|
streamDiagnostics = [
|
||||||
{
|
{
|
||||||
|
|
@ -177,8 +195,8 @@
|
||||||
streamState = 'connecting';
|
streamState = 'connecting';
|
||||||
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||||
const ws = new WebSocket(
|
const ws = new WebSocket(
|
||||||
`${protocol}//${window.location.host}/api/runtimes/${encodeURIComponent(runtimeId)}/workers/${encodeURIComponent(
|
`${protocol}//${window.location.host}/api/runtimes/${encodeURIComponent(target.runtimeId)}/workers/${encodeURIComponent(
|
||||||
workerId
|
target.workerId
|
||||||
)}/events/ws`
|
)}/events/ws`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -261,12 +279,14 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
|
const target = consoleTarget;
|
||||||
observedEvents = [];
|
observedEvents = [];
|
||||||
streamDiagnostics = [];
|
streamDiagnostics = [];
|
||||||
void refreshConsole();
|
advanceReloadToken();
|
||||||
|
void loadConsoleData(target);
|
||||||
});
|
});
|
||||||
|
|
||||||
$effect(() => connectObservation(worker, reloadToken));
|
$effect(() => connectObservation(worker, reloadToken, consoleTarget));
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user