From 6b56accec842c05244ab921f9481dee3f181d1e5 Mon Sep 17 00:00:00 2001 From: LukeGus Date: Sun, 20 Sep 2026 20:24:28 -0500 Subject: [PATCH] fix: host key updates not syncing, metrics 404 race on first connect Host key writes never bumped updatedAt so sync never picked them up. Also retry the first metrics fetch briefly instead of failing right away. --- .../repositories/host-resolution-repository.ts | 6 ++++-- src/ui/features/host-metrics/HostMetricsTab.tsx | 10 +++++++++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/backend/database/repositories/host-resolution-repository.ts b/src/backend/database/repositories/host-resolution-repository.ts index 811d23395..960a02971 100644 --- a/src/backend/database/repositories/host-resolution-repository.ts +++ b/src/backend/database/repositories/host-resolution-repository.ts @@ -1,4 +1,4 @@ -import { and, eq, inArray, isNotNull } from "drizzle-orm"; +import { and, eq, inArray, isNotNull, sql } from "drizzle-orm"; import { hosts, sshCredentials, sshFolders } from "../db/schema.js"; import type { DatabaseContext } from "./database-context.js"; import { DataCrypto } from "../../utils/data-crypto.js"; @@ -326,6 +326,7 @@ export class HostResolutionRepository { hostKeyAlgorithm: algorithm, hostKeyFirstSeen: now, hostKeyLastVerified: now, + updatedAt: sql`CURRENT_TIMESTAMP`, }) .where(eq(hosts.id, hostId)); await this.afterWrite(); @@ -347,6 +348,7 @@ export class HostResolutionRepository { hostKeyAlgorithm: algorithm, hostKeyLastVerified: now, hostKeyChangedCount: currentChangeCount + 1, + updatedAt: sql`CURRENT_TIMESTAMP`, }) .where(eq(hosts.id, hostId)); await this.afterWrite(); @@ -358,7 +360,7 @@ export class HostResolutionRepository { ): Promise { await this.context.drizzle .update(hosts) - .set({ hostKeyLastVerified: now }) + .set({ hostKeyLastVerified: now, updatedAt: sql`CURRENT_TIMESTAMP` }) .where(eq(hosts.id, hostId)); await (this.onLazyWrite?.() ?? this.afterWrite()); } diff --git a/src/ui/features/host-metrics/HostMetricsTab.tsx b/src/ui/features/host-metrics/HostMetricsTab.tsx index 837609732..9bad7b33c 100644 --- a/src/ui/features/host-metrics/HostMetricsTab.tsx +++ b/src/ui/features/host-metrics/HostMetricsTab.tsx @@ -373,7 +373,15 @@ function HostMetricsInner({ if (result.viewerSessionId) setViewerSessionId(result.viewerSessionId); } - const data = await getServerMetricsById(currentHostConfig.id); + // The connect above only opens the SSH session; the first real sample is + // collected asynchronously on the backend (status check, then metrics + // exec), so it isn't ready the instant the connection succeeds. Give it + // a few short retries before treating the initial fetch as a failure. + let data = await getServerMetricsById(currentHostConfig.id); + for (let i = 0; !data && i < 5; i++) { + await new Promise((resolve) => setTimeout(resolve, 1500)); + data = await getServerMetricsById(currentHostConfig.id); + } if (!data) { throw new Error(t("hostMetrics.connectionFailed")); }