fix: map internal worker terminal lifecycles
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
workspaceWorkersStore,
|
||||
type SidebarWorker,
|
||||
} from './worker-subscription';
|
||||
import { canShowWorkerInSidebar } from './workers';
|
||||
import { canShowWorkerInSidebar, sidebarWorkerActivity } from './workers';
|
||||
|
||||
const COLLAPSED_WORKER_COUNT = 6;
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
<ul class="nav-list" aria-label="Workers">
|
||||
{#each visibleWorkers as worker (`${worker.runtime_id}:${worker.worker_id}`)}
|
||||
{@const href = workerConsoleHref(worker, workspaceId)}
|
||||
{@const activity = sidebarWorkerActivity(worker)}
|
||||
<li>
|
||||
<a
|
||||
href={href}
|
||||
@@ -77,11 +78,11 @@
|
||||
aria-current={currentPath === href ? 'page' : undefined}
|
||||
>
|
||||
<span class="worker-status-indicator">
|
||||
{#if worker.state === 'running'}
|
||||
{#if activity === 'worker-running'}
|
||||
<span class="worker-status-spinner"><Spinner label="Running" /></span>
|
||||
{:else if worker.has_running_internal_workers}
|
||||
{:else if activity === 'subworker-running'}
|
||||
<span class="worker-status-spinner is-subworker"><Spinner label="SubWorker running" /></span>
|
||||
{:else if worker.state === 'idle'}
|
||||
{:else if activity === 'idle'}
|
||||
<span class="worker-status-dot" aria-label="Idle"></span>
|
||||
{/if}
|
||||
</span>
|
||||
|
||||
@@ -14,13 +14,18 @@ declare const Deno: {
|
||||
test(name: string, fn: () => void | Promise<void>): void;
|
||||
};
|
||||
|
||||
function worker(runtimeId: string, workerId: string, revision: number): SubscriptionWorker {
|
||||
function worker(
|
||||
runtimeId: string,
|
||||
workerId: string,
|
||||
revision: number,
|
||||
hasRunningInternalWorkers = false,
|
||||
): SubscriptionWorker {
|
||||
return {
|
||||
worker_id: workerId,
|
||||
runtime_id: runtimeId,
|
||||
subject_revision: revision,
|
||||
state: 'idle',
|
||||
has_running_internal_workers: false,
|
||||
has_running_internal_workers: hasRunningInternalWorkers,
|
||||
workspace_id: 'workspace-test',
|
||||
display_name: null,
|
||||
profile: null,
|
||||
@@ -88,3 +93,28 @@ Deno.test('workspace Worker reducer ignores stale events and removes composite s
|
||||
assertEquals(projection.workers.size, 0);
|
||||
assertEquals(projection.revisions.get('runtime-a:1'), 4);
|
||||
});
|
||||
|
||||
Deno.test('fatal child stop replaces the running-child sidebar projection', () => {
|
||||
const projection = createWorkspaceWorkersProjection();
|
||||
projection.workers.set('runtime-a:1', worker('runtime-a', '1', 1, true));
|
||||
projection.revisions.set('runtime-a:1', 1);
|
||||
|
||||
applyWorkspaceWorkersFrame(projection, {
|
||||
protocol_version: 1,
|
||||
frame: 'event',
|
||||
message: {
|
||||
event: 'event',
|
||||
data: {
|
||||
subscription_id: 'subscription-1',
|
||||
subject_revision: 2,
|
||||
payload: {
|
||||
event: 'worker_upserted',
|
||||
data: { worker: worker('runtime-a', '1', 2, false) },
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assertEquals(projection.workers.get('runtime-a:1')?.has_running_internal_workers, false);
|
||||
assertEquals(projection.revisions.get('runtime-a:1'), 2);
|
||||
});
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
canOpenWorkerConsole,
|
||||
canShowWorkerInSidebar,
|
||||
compareWorkersForSidebar,
|
||||
sidebarWorkerActivity,
|
||||
} from "./workers.ts";
|
||||
import type { Worker } from "./types.ts";
|
||||
|
||||
@@ -77,3 +78,21 @@ Deno.test("sidebar workers sort running then idle then stopped", () => {
|
||||
workers.sort(compareWorkersForSidebar);
|
||||
assertEquals(workers.map((candidate) => candidate.worker_id).join(","), "2,1,4,3");
|
||||
});
|
||||
|
||||
Deno.test("fatal child stop clears the sidebar SubWorker spinner activity", () => {
|
||||
const parent = { state: "idle", has_running_internal_workers: true };
|
||||
assertEquals(sidebarWorkerActivity(parent), "subworker-running");
|
||||
|
||||
parent.has_running_internal_workers = false;
|
||||
assertEquals(sidebarWorkerActivity(parent), "idle");
|
||||
});
|
||||
|
||||
Deno.test("stopped parents do not fall back to the idle indicator", () => {
|
||||
assertEquals(
|
||||
sidebarWorkerActivity({
|
||||
state: "stopped",
|
||||
has_running_internal_workers: false,
|
||||
}),
|
||||
"none",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,5 +1,24 @@
|
||||
import type { Worker } from './types';
|
||||
|
||||
export type SidebarWorkerActivity =
|
||||
| 'worker-running'
|
||||
| 'subworker-running'
|
||||
| 'idle'
|
||||
| 'none';
|
||||
|
||||
type WorkerActivitySource = Pick<Worker, 'state'> & {
|
||||
has_running_internal_workers: boolean;
|
||||
};
|
||||
|
||||
export function sidebarWorkerActivity(
|
||||
worker: WorkerActivitySource,
|
||||
): SidebarWorkerActivity {
|
||||
if (worker.state === 'running') return 'worker-running';
|
||||
if (worker.has_running_internal_workers) return 'subworker-running';
|
||||
if (worker.state === 'idle') return 'idle';
|
||||
return 'none';
|
||||
}
|
||||
|
||||
export function canShowWorkerInSidebar(worker: Worker): boolean {
|
||||
return worker.implementation.kind !== 'backend_worker_registry';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user