fix: simplify host status to online/offline and keep it live without a refresh

This commit is contained in:
LukeGus committed 2026-10-04 14:18:50 -05:00
1 parent 2646b649d7
commit 0a436ab3d8
48 files changed
+549 -789

No files matched your search

+1 -12
View File
@@ -347,11 +347,8 @@ export class MetricsPoller {
const settings = await this.settingsFor(host.id);
if (!settings.metricsEnabled) return;
let authenticated = false;
try {
const metrics = await collectMetrics(this.deps, host, settings, () => {
authenticated = true;
});
const metrics = await collectMetrics(this.deps, host, settings);
this.metrics.set(host.id, { data: metrics, timestamp: Date.now() });
this.ctx.hosts.status.reportLogin(host.id, { ok: true });
this.setCollectionState(host, "collecting");
@@ -367,14 +364,6 @@ export class MetricsPoller {
const hostKeyChanged = isHostKeyVerificationError(error);
const message = error instanceof Error ? error.message : "";
const isAuthError = /authentication|permission denied/i.test(message);
// A timeout or a dropped connection says nothing about the login.
if (!authenticated && (isAuthError || hostKeyChanged)) {
this.ctx.hosts.status.reportLogin(host.id, {
ok: false,
hostKeyChanged,
});
}
this.setCollectionState(
host,
hostKeyChanged
+2 -3
View File
@@ -1,8 +1,7 @@
import type { PluginHostStatus } from "@termix/plugin-sdk/backend";
import type { CpuSamples } from "./widgets/cpu-collector.js";
import { createNetworkSamples } from "./widgets/network-collector.js";
export type HostStatus = "online" | "reachable" | "offline";
export class RequestQueue {
private queues = new Map<number, Array<() => Promise<unknown>>>();
private processing = new Set<number>();
@@ -418,7 +417,7 @@ export class HostPollCache<THost extends { id: number } = { id: number }> {
* host answers. A host core does not check (status checks off) is tried.
*/
export function canStartInitialMetrics(
status: HostStatus | null | undefined,
status: PluginHostStatus | null | undefined,
hasViewers: boolean,
): boolean {
return hasViewers && status !== "offline";
@@ -40,7 +40,7 @@ function setup(hostIds = [7]) {
hostStatuses: Object.fromEntries(
hostIds.map((id) => [
id,
{ status: "reachable" as const, lastChecked: "now" },
{ status: "online" as const, lastChecked: "now" },
]),
),
});
@@ -131,13 +131,13 @@ describe("MetricsPoller", () => {
expect(collectMetrics).not.toHaveBeenCalled();
// Core's check comes back: the first sample runs.
fake.hostStatuses.set(7, { status: "reachable", lastChecked: "now" });
poller.hostStatusChanged(7, "reachable");
fake.hostStatuses.set(7, { status: "online", lastChecked: "now" });
poller.hostStatusChanged(7, "online");
await flush();
expect(collectMetrics).toHaveBeenCalledOnce();
});
it("reports a failed login and why collection stopped", async () => {
it("says why collection stopped without touching the status", async () => {
collectMetrics.mockRejectedValue(
new Error("All configured authentication methods failed"),
);
@@ -146,9 +146,7 @@ describe("MetricsPoller", () => {
poller.registerViewer(7, "viewer-a", "user-1");
await flush();
expect(fake.statusReports).toEqual([
{ hostId: 7, ok: false, hostKeyChanged: false },
]);
expect(fake.statusReports).toEqual([]);
expect(fake.emitted.at(-1)?.payload).toMatchObject({
state: "auth_failed",
});
@@ -174,9 +172,7 @@ describe("MetricsPoller", () => {
poller.registerViewer(7, "viewer-a", "user-1");
await flush();
expect(fake.statusReports).toEqual([
{ hostId: 7, ok: false, hostKeyChanged: true },
]);
expect(fake.statusReports).toEqual([]);
expect(state.authFailures.shouldSkip(7)).toBe(true);
poller.hostKeyAccepted(7);
expect(state.authFailures.shouldSkip(7)).toBe(false);
@@ -27,7 +27,6 @@ describe("auth failure tracking", () => {
describe("initial metrics admission", () => {
it("needs a viewer and a host core does not see as offline", () => {
expect(canStartInitialMetrics("online", true)).toBe(true);
expect(canStartInitialMetrics("reachable", true)).toBe(true);
expect(canStartInitialMetrics("offline", true)).toBe(false);
expect(canStartInitialMetrics("online", false)).toBe(false);
// Status checks off: core has no status, so the sample is tried.