fix: fall back from offline routed machines

This commit is contained in:
Marc Kassubeck
2026-05-26 22:35:42 +02:00
parent 159f5332ed
commit e352dce6ef
4 changed files with 139 additions and 8 deletions
@@ -1,16 +1,16 @@
import { api, type Machine } from "../api";
import { api, type Machine, type MachineHealth } from "../api";
import { resetWorkspaceScopedState } from "../appState";
import type { GetState, SetState, UpdateUrl } from "./types";
import type { ProjectController } from "./projectController";
export class MachineController {
constructor(private readonly getState: GetState, private readonly setState: SetState, private readonly updateUrl: UpdateUrl, private readonly projects: ProjectController) {}
constructor(private readonly getState: GetState, private readonly setState: SetState, private readonly updateUrl: UpdateUrl, private readonly projects: Pick<ProjectController, "loadProjects">) {}
async loadMachines(routeMachineId?: string): Promise<void> {
this.setState({ error: "", isLoadingMachines: true });
try {
const machines = await api.machines();
const selectedMachine = machines.find((machine) => machine.id === (routeMachineId ?? "local")) ?? machines.find((machine) => machine.id === "local") ?? machines[0];
const selectedMachine = await this.selectInitialMachine(machines, routeMachineId);
this.setState({ machines, selectedMachine });
void this.refreshMachineHealthFor(machines);
} catch (error) {
@@ -82,6 +82,39 @@ export class MachineController {
}
}
private async selectInitialMachine(machines: Machine[], routeMachineId?: string): Promise<Machine | undefined> {
const requestedMachine = machines.find((machine) => machine.id === (routeMachineId ?? "local"));
if (requestedMachine?.kind !== "remote") return requestedMachine ?? this.localMachine(machines);
const health = await this.safeRemoteHealth(requestedMachine);
if (health.ok) return requestedMachine;
const local = this.localMachine(machines);
this.setState({
error: `${requestedMachine.name} is offline; showing ${local?.name ?? "another machine"} instead.`,
machineStatuses: { ...this.getState().machineStatuses, [health.machineId]: health },
});
return local ?? requestedMachine;
}
private async safeRemoteHealth(machine: Machine): Promise<MachineHealth> {
try {
return await api.health(machine.id);
} catch (error) {
return {
machineId: machine.id,
ok: false,
checkedAt: new Date().toISOString(),
status: "offline",
error: error instanceof Error ? error.message : String(error),
};
}
}
private localMachine(machines: Machine[]): Machine | undefined {
return machines.find((machine) => machine.id === "local") ?? machines[0];
}
private async refreshMachineHealthFor(machines: Machine[]): Promise<void> {
const results = await Promise.allSettled(machines.map((machine) => api.health(machine.id)));
const health = Object.fromEntries(results.flatMap((result) => result.status === "fulfilled" ? [[result.value.machineId, result.value] as const] : []));