feat(desktop-client): queue account probes and report health to server

Replace serial probe-on-lock with a bounded probe queue (concurrency 3) that
adds a "queued" probe state, manual cooldown, and retry backoff. After each
probe the runtime debounces a batched POST to the new
/desktop/accounts/health-reports endpoint so the server learns about live,
expired, and risk transitions without waiting for a re-bind. Adds an
account-scoped IPC (probeRuntimeAccount + runtimeAccountSnapshot) so the
renderer can refresh a single row instead of replaying the full snapshot,
and exposes the resulting "重新校验" action in AccountsView/AiPlatformsView.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-27 21:33:55 +08:00
parent 051976e4a9
commit c3feb7477a
15 changed files with 817 additions and 129 deletions
+13 -1
View File
@@ -24,12 +24,13 @@ import { registerRendererDevtoolsProxyTarget } from "./renderer-devtools-proxy";
import { onRuntimeInvalidated } from "./runtime-events";
import {
noteRuntimeAccountBound,
requestRuntimeAccountProbe,
refreshRuntimeAccounts,
releaseRuntimeSession,
syncRuntimeSession,
unbindRuntimeAccount,
} from "./runtime-controller";
import { createRuntimeSnapshot } from "./runtime-snapshot";
import { createRuntimeAccountSnapshot, createRuntimeSnapshot } from "./runtime-snapshot";
import { resolveDesktopClientID, resolveDesktopDeviceInfo } from "./device-id";
import { initScheduler } from "./scheduler";
import { initSessionRegistry } from "./session-registry";
@@ -154,6 +155,10 @@ function captureRuntimeSnapshot() {
return snapshot;
}
function captureRuntimeAccountSnapshot(accountId: string) {
return createRuntimeAccountSnapshot(accountId);
}
async function ensureMainWindow(): Promise<ElectronBrowserWindow> {
const existing = currentMainWindow();
if (existing) {
@@ -314,6 +319,9 @@ function registerBridgeHandlers(): void {
}),
);
ipcMain.handle("desktop:runtime-snapshot", () => captureRuntimeSnapshot());
ipcMain.handle("desktop:runtime-account-snapshot", (_event, accountId: string) =>
captureRuntimeAccountSnapshot(accountId),
);
safeHandle("desktop:bind-publish-account", async (_event, platformId: string) => {
const account = (await bindPublishAccount(platformId)) as DesktopAccountInfo;
noteRuntimeAccountBound(account);
@@ -328,6 +336,10 @@ function registerBridgeHandlers(): void {
await refreshRuntimeAccounts();
return null;
});
safeHandle("desktop:probe-runtime-account", async (_event, accountId: string) => {
requestRuntimeAccountProbe(accountId);
return captureRuntimeAccountSnapshot(accountId);
});
safeHandle(
"desktop:open-publish-account-console",
async (