Merge remote-tracking branch 'origin/work/T-674-backend-job-runner' into develop
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -279,6 +279,8 @@ export type SubscriptionWorkerWorkdirAttachment = {
|
||||
*/
|
||||
alias: string, repository_key?: string | null, working_directory_id: SubscriptionWorkdirId, };
|
||||
|
||||
export type SubscriptionWorkerJob = { job_id: string, attempt_id: string, purpose: string, };
|
||||
|
||||
export type SubscriptionWorker = { worker_id: SubscriptionWorkerId,
|
||||
/**
|
||||
* Set by the Workspace Server when projecting a Runtime-owned Worker to clients.
|
||||
@@ -307,7 +309,12 @@ worker_state?: WorkerStateSnapshot | null,
|
||||
/**
|
||||
* Runtime catalog lifecycle compatibility projection; not foreground-state authority.
|
||||
*/
|
||||
state: SubscriptionWorkerState, has_running_internal_workers: boolean, workspace_id?: string | null, display_name?: string | null, profile?: string | null, workdir_attachments?: Array<SubscriptionWorkerWorkdirAttachment>, };
|
||||
state: SubscriptionWorkerState, has_running_internal_workers: boolean, workspace_id?: string | null, display_name?: string | null, profile?: string | null,
|
||||
/**
|
||||
* Backend-owned Job binding. Runtime producers leave this unset; the
|
||||
* Workspace projection enriches both snapshots and live updates.
|
||||
*/
|
||||
job?: SubscriptionWorkerJob | null, workdir_attachments?: Array<SubscriptionWorkerWorkdirAttachment>, };
|
||||
|
||||
export type WorkspaceSubscriptionWorkdir = { working_directory_id: SubscriptionWorkdirId, repository_key: string, state: string, };
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import type {
|
||||
Event as PodProtocolEvent,
|
||||
Method as PodProtocolMethod,
|
||||
Segment as PodProtocolSegment,
|
||||
SubscriptionWorkerJob,
|
||||
WorkerStateSnapshot,
|
||||
} from "$lib/generated/protocol";
|
||||
import type {
|
||||
@@ -88,6 +89,7 @@ export type Worker =
|
||||
display_name: string;
|
||||
tags: string[];
|
||||
worker_state?: WorkerStateSnapshot | null;
|
||||
job?: SubscriptionWorkerJob | null;
|
||||
diagnostics: Diagnostic[];
|
||||
};
|
||||
|
||||
|
||||
@@ -88,6 +88,47 @@ Deno.test('workspace Worker snapshot keeps equal local ids from different Runtim
|
||||
assertEquals([...projection.workers.keys()].sort(), ['runtime-a:1', 'runtime-b:1']);
|
||||
});
|
||||
|
||||
Deno.test('workspace Worker snapshot and live update preserve canonical Job metadata', () => {
|
||||
const projection = createWorkspaceWorkersProjection();
|
||||
const snapshotWorker = worker('runtime-a', 'job-worker', 1);
|
||||
snapshotWorker.job = {
|
||||
job_id: 'check:T-1:r1',
|
||||
attempt_id: 'check:T-1:r1:attempt:1',
|
||||
purpose: 'ticket_item_check',
|
||||
};
|
||||
applyWorkspaceWorkersFrame(projection, {
|
||||
protocol_version: 1,
|
||||
frame: 'response',
|
||||
message: {
|
||||
result: 'subscribed',
|
||||
payload: {
|
||||
request_id: 'request-1',
|
||||
subscription_id: 'subscription-1',
|
||||
selector: { topic: 'workspace_workers' },
|
||||
snapshot_revision: 1,
|
||||
snapshot: { topic: 'workers', data: { workers: [snapshotWorker] } },
|
||||
},
|
||||
},
|
||||
});
|
||||
assertEquals(projection.workers.get('runtime-a:job-worker')?.job, snapshotWorker.job);
|
||||
|
||||
const updated = { ...snapshotWorker, subject_revision: 2 };
|
||||
updated.job = { ...snapshotWorker.job, attempt_id: 'check:T-1:r1:attempt:2' };
|
||||
applyWorkspaceWorkersFrame(projection, {
|
||||
protocol_version: 1,
|
||||
frame: 'event',
|
||||
message: {
|
||||
event: 'event',
|
||||
data: {
|
||||
subscription_id: 'subscription-1',
|
||||
subject_revision: 2,
|
||||
payload: { event: 'worker_upserted', data: { worker: updated } },
|
||||
},
|
||||
},
|
||||
});
|
||||
assertEquals(projection.workers.get('runtime-a:job-worker')?.job, updated.job);
|
||||
});
|
||||
|
||||
Deno.test('workspace Worker reducer ignores stale events and removes composite subject', () => {
|
||||
const projection = createWorkspaceWorkersProjection();
|
||||
projection.workers.set('runtime-a:1', worker('runtime-a', '1', 3));
|
||||
|
||||
@@ -143,6 +143,7 @@ function projectWorker(
|
||||
display_name: displayName,
|
||||
label: displayName,
|
||||
profile: worker.profile ?? null,
|
||||
job: worker.job ?? null,
|
||||
tags: [],
|
||||
workspace: {
|
||||
visibility: "workspace",
|
||||
|
||||
@@ -63,6 +63,19 @@ Deno.test("live runtime workers are sidebar targets and console targets", () =>
|
||||
assertEquals(canOpenWorkerConsole(liveWorker), true);
|
||||
});
|
||||
|
||||
Deno.test("Backend Job Workers are hidden only from the sidebar View", () => {
|
||||
const jobWorker = worker({
|
||||
state: "running",
|
||||
job: {
|
||||
job_id: "check:T-1:r1",
|
||||
attempt_id: "check:T-1:r1:attempt:1",
|
||||
purpose: "ticket_item_check",
|
||||
},
|
||||
});
|
||||
assertEquals(canShowWorkerInSidebar(jobWorker), false);
|
||||
assertEquals(canOpenWorkerConsole(jobWorker), true);
|
||||
});
|
||||
|
||||
Deno.test("sidebar workers sort running then idle then stopped", () => {
|
||||
const workers = [
|
||||
worker({ worker_id: "3", display_name: "Stopped", state: "stopped" }),
|
||||
|
||||
@@ -22,15 +22,15 @@ export function sidebarWorkerActivity(
|
||||
}
|
||||
|
||||
export function canShowWorkerInSidebar(
|
||||
worker: Pick<Worker, 'implementation'>,
|
||||
worker: Pick<Worker, 'implementation' | 'job'>,
|
||||
): boolean {
|
||||
return worker.implementation.kind !== 'backend_worker_registry';
|
||||
return !worker.job && worker.implementation.kind !== 'backend_worker_registry';
|
||||
}
|
||||
|
||||
export function canOpenWorkerConsole(
|
||||
worker: Pick<Worker, 'implementation'>,
|
||||
): boolean {
|
||||
return canShowWorkerInSidebar(worker);
|
||||
return worker.implementation.kind !== 'backend_worker_registry';
|
||||
}
|
||||
|
||||
type SidebarWorkerLink = Pick<Worker, 'resource_key' | 'display_name'>;
|
||||
|
||||
Reference in New Issue
Block a user