feat(system): add Worker 006 telemetry and network profile

This commit is contained in:
DCCONSTRUCTIONS
2026-07-27 21:06:51 +03:00
parent 438196cd6d
commit 67e12a47a4
17 changed files with 2723 additions and 8 deletions
@@ -0,0 +1,47 @@
import { useCallback, useEffect, useState } from "react";
import {
fetchWorkerTelemetry,
type WorkerTelemetry,
} from "./workerTelemetry";
export interface WorkerTelemetryState {
telemetry: WorkerTelemetry | null;
loading: boolean;
error: string | null;
refresh: () => void;
}
export function useWorkerTelemetry(pollMilliseconds = 10_000): WorkerTelemetryState {
const [telemetry, setTelemetry] = useState<WorkerTelemetry | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [generation, setGeneration] = useState(0);
const refresh = useCallback(() => setGeneration((value) => value + 1), []);
useEffect(() => {
const controller = new AbortController();
setLoading(true);
void fetchWorkerTelemetry(controller.signal)
.then((document) => {
if (controller.signal.aborted) return;
setTelemetry(document);
setError(null);
})
.catch((reason: unknown) => {
if (controller.signal.aborted) return;
setError(reason instanceof Error ? reason.message : "Worker 006 не ответил.");
})
.finally(() => {
if (!controller.signal.aborted) setLoading(false);
});
return () => controller.abort();
}, [generation]);
useEffect(() => {
const timer = window.setInterval(refresh, pollMilliseconds);
return () => window.clearInterval(timer);
}, [pollMilliseconds, refresh]);
return { telemetry, loading, error, refresh };
}
@@ -0,0 +1,249 @@
export interface WorkerConnectionProfile {
schema_version: "missioncore.worker-connection-profile/v1";
profile_id: string;
display_name: string;
expected_node_id: string;
ssh_host_alias: string;
address: string;
port: number;
revision: number;
updated_at_utc: string | null;
}
export interface WorkerProbe {
schema_version: "missioncore.worker-probe/v1";
reachable: boolean;
identity_matches: boolean;
node_id: string | null;
latency_ms: number | null;
observed_at_utc: string;
error_code: string | null;
}
export interface WorkerProfileDocument {
schema_version: "missioncore.worker-connection-profile/v1";
profile: WorkerConnectionProfile;
security: {
transport: "ssh";
host_key_policy: "strict-pinned";
credentials_managed_by_ui: false;
ssh_host_alias: string;
};
}
export interface WorkerRuntime {
name: string;
role: string;
owner: "mission-core" | "external";
external: boolean;
image: string | null;
state: string;
health: string | null;
cpu_percent: number | null;
memory_percent: number | null;
memory_usage: string | null;
network_io: string | null;
block_io: string | null;
pids: number | null;
}
export interface WorkerPipelineStage {
id: string;
label: string;
state: "active" | "waiting" | "ready" | "unavailable";
}
export interface WorkerTelemetryHistoryRow {
observed_at_utc: string;
cpu_percent: number | null;
memory_percent: number | null;
gpu_percent: number | null;
gpu_memory_percent: number | null;
network_receive_bytes_per_second: number | null;
network_send_bytes_per_second: number | null;
}
export interface WorkerNetworkInterface {
name: string;
description: string | null;
status: string | null;
link_speed_bps: number | null;
mac_address: string | null;
addresses: string[];
received_bytes: number | null;
sent_bytes: number | null;
}
export interface WorkerTelemetry {
schema_version: "missioncore.worker-telemetry/v1";
profile: WorkerConnectionProfile;
connection: WorkerProbe;
node: {
node_id: string;
observed_at_utc: string;
os: {
caption?: string;
version?: string;
uptime_seconds?: number;
};
cpu: {
name?: string;
logical_processors?: number;
load_percent?: number;
};
memory: {
total_bytes: number | null;
used_bytes: number | null;
free_bytes: number | null;
used_percent: number | null;
};
disks: Array<{
name?: string;
size_bytes?: number;
free_bytes?: number;
}>;
gpu: {
name?: string;
utilization_percent?: number;
memory_used_mib?: number;
memory_total_mib?: number;
power_watts?: number;
temperature_celsius?: number;
memory_used_percent?: number;
} | null;
triton: {
ready: boolean;
requests_succeeded: number | null;
requests_failed: number | null;
inferences: number | null;
};
} | null;
runtimes: WorkerRuntime[];
pipeline: {
service_state: string;
current_stage: string | null;
active_request_id: string | null;
active_frame_index: number | null;
completed_runs: number | null;
failed_runs: number | null;
model_load_seconds: number | null;
stages: WorkerPipelineStage[];
};
network: {
interfaces: WorkerNetworkInterface[];
aggregate: {
received_bytes: number;
sent_bytes: number;
receive_bytes_per_second: number | null;
send_bytes_per_second: number | null;
} | null;
};
history: WorkerTelemetryHistoryRow[];
}
export interface WorkerProfileMutation {
revision: number;
address: string;
port: number;
}
function isRecord(value: unknown): value is Record<string, unknown> {
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
}
function requireJsonRecord(value: unknown, schema: string): Record<string, unknown> {
if (!isRecord(value) || value.schema_version !== schema) {
throw new Error("Ответ системной телеметрии не соответствует контракту.");
}
return value;
}
async function requestJson(
url: string,
init: RequestInit,
): Promise<unknown> {
const response = await fetch(url, {
...init,
headers: {
Accept: "application/json",
...(init.body ? { "Content-Type": "application/json" } : {}),
...init.headers,
},
});
if (!response.ok) {
throw new Error(`Системный API вернул HTTP ${response.status}.`);
}
return response.json();
}
export async function fetchWorkerTelemetry(
signal?: AbortSignal,
): Promise<WorkerTelemetry> {
const document = requireJsonRecord(
await requestJson("/api/v1/system/worker-telemetry?history=90", {
method: "GET",
signal,
}),
"missioncore.worker-telemetry/v1",
);
if (
!isRecord(document.connection)
|| !isRecord(document.profile)
|| !Array.isArray(document.runtimes)
|| !isRecord(document.pipeline)
|| !isRecord(document.network)
|| !Array.isArray(document.history)
) {
throw new Error("Срез Worker 006 неполон.");
}
return document as unknown as WorkerTelemetry;
}
export async function fetchWorkerProfile(
signal?: AbortSignal,
): Promise<WorkerProfileDocument> {
const document = requireJsonRecord(
await requestJson("/api/v1/system/worker-profile", {
method: "GET",
signal,
}),
"missioncore.worker-connection-profile/v1",
);
if (!isRecord(document.profile) || !isRecord(document.security)) {
throw new Error("Профиль Worker 006 неполон.");
}
return document as unknown as WorkerProfileDocument;
}
export async function testWorkerProfile(
request: WorkerProfileMutation,
signal?: AbortSignal,
): Promise<WorkerProbe> {
const document = requireJsonRecord(
await requestJson("/api/v1/system/worker-profile/test", {
method: "POST",
body: JSON.stringify(request),
signal,
}),
"missioncore.worker-probe/v1",
);
return document as unknown as WorkerProbe;
}
export async function saveWorkerProfile(
request: WorkerProfileMutation,
signal?: AbortSignal,
): Promise<WorkerProfileDocument & { verification: WorkerProbe }> {
const document = requireJsonRecord(
await requestJson("/api/v1/system/worker-profile", {
method: "PUT",
body: JSON.stringify(request),
signal,
}),
"missioncore.worker-connection-profile/v1",
);
if (!isRecord(document.profile) || !isRecord(document.verification)) {
throw new Error("Сохранённый профиль Worker 006 неполон.");
}
return document as unknown as WorkerProfileDocument & { verification: WorkerProbe };
}