diff --git a/scripts/comfy-host-agent.mjs b/scripts/comfy-host-agent.mjs index 6f64bed..919301e 100644 --- a/scripts/comfy-host-agent.mjs +++ b/scripts/comfy-host-agent.mjs @@ -677,10 +677,27 @@ const server = http.createServer(async (req, res) => { markWork() return json(res, 200, { ok: true, started: false, already: true, asleep: false, port: healthyPort, proxyPort }) } - if (lastLaunchAt && Date.now() - lastLaunchAt < 60_000) { + const listenPort = desktopListenPort() + const processAlive = lastProcessUp || await processUp().catch(() => false) || await pythonMainUp().catch(() => false) + const portBusy = await portInUse(listenPort) + const recentlySlow = [...probeSkipUntil.entries()].some(([, until]) => Date.now() < until) + if (processAlive || portBusy || recentlySlow) { + markWork() + lastProcessUp = true + if (portBusy) setProxyTarget(listenPort) + return json(res, 200, { + ok: true, + started: false, + already: true, + booting: true, + asleep: false, + port: portBusy ? listenPort : null, + proxyPort + }) + } + if (lastLaunchAt && Date.now() - lastLaunchAt < 5 * 60_000) { return json(res, 200, { ok: true, started: false, already: true, booting: true, asleep: false, proxyPort }) } - await taskkillImage('Comfy Desktop.exe') stoppedByAgent = false lastLaunchAt = Date.now() const launched = await startComfy() diff --git a/server/utils/comfyLifecycle.ts b/server/utils/comfyLifecycle.ts index d28fc7a..c3fee66 100644 --- a/server/utils/comfyLifecycle.ts +++ b/server/utils/comfyLifecycle.ts @@ -52,15 +52,16 @@ export async function checkComfyHttp(timeoutMs = 5000, host?: string) { let resolved = host || '' try { if (!resolved) { - if (!comfyConfigured()) return { ok: false as const, host: '', status: 0, stats: null } + if (!comfyConfigured()) return { ok: false as const, host: '', status: 0, stats: null, timedOut: false } resolved = getComfyHost() } const res = await fetch(`${resolved}/system_stats`, { signal: AbortSignal.timeout(timeoutMs) }) - if (!res.ok) return { ok: false as const, host: resolved, status: res.status, stats: null } + if (!res.ok) return { ok: false as const, host: resolved, status: res.status, stats: null, timedOut: false } const stats = await res.json().catch(() => null) - return { ok: true as const, host: resolved, status: res.status, stats } - } catch { - return { ok: false as const, host: resolved, status: 0, stats: null } + return { ok: true as const, host: resolved, status: res.status, stats, timedOut: false } + } catch (error) { + const timedOut = error instanceof Error && (error.name === 'TimeoutError' || error.name === 'AbortError' || /timeout/i.test(error.message)) + return { ok: false as const, host: resolved, status: 0, stats: null, timedOut } } } @@ -348,6 +349,24 @@ async function ensureUnlocked(onStatus: StatusFn, skipBusyWait = false) { onStatus({ state: 'online', message: 'ComfyUI online', host }) return } + if (health.timedOut) { + log('http-busy', { host, timeoutMs: cfg.healthTimeoutMs }) + const retry = await checkComfyHttp(Math.max(cfg.healthTimeoutMs, 12_000)) + if (retry.ok) { + if (!skipBusyWait) await waitWhileBusy(onStatus) + onStatus({ state: 'online', message: 'ComfyUI online', host }) + return + } + onStatus({ + state: 'busy', + message: 'ComfyUI is loaded but slow to answer. Not starting another instance.', + host, + processRunning: true + }) + if (!skipBusyWait) await waitWhileBusy(onStatus) + onStatus({ state: 'online', message: 'ComfyUI online', host, processRunning: true }) + return + } log('http-fail', { host }) const remote = await controlRequest('/status') @@ -383,11 +402,9 @@ async function ensureUnlocked(onStatus: StatusFn, skipBusyWait = false) { onStatus({ state: 'online', message: 'ComfyUI online', host, processRunning: true }) return } - onStatus({ - state: 'starting', - message: 'ComfyUI is running but the API never came up. Attempting a relaunch...', - host, - processRunning: true + throw createError({ + statusCode: 503, + statusMessage: 'ComfyUI is running but the API never came up. Not launching a second instance.' }) } diff --git a/server/utils/imageComfyLifecycle.ts b/server/utils/imageComfyLifecycle.ts index 428e071..46dc6f8 100644 --- a/server/utils/imageComfyLifecycle.ts +++ b/server/utils/imageComfyLifecycle.ts @@ -55,16 +55,17 @@ export async function checkImageComfyHttp(timeoutMs = 5000, host?: string) { let resolved = host || '' try { if (!resolved) { - if (!imageComfyConfigured()) return { ok: false as const, host: '', status: 0, stats: null } + if (!imageComfyConfigured()) return { ok: false as const, host: '', status: 0, stats: null, timedOut: false } resolved = getImageComfyHost() } - if (!resolved) return { ok: false as const, host: '', status: 0, stats: null } + if (!resolved) return { ok: false as const, host: '', status: 0, stats: null, timedOut: false } const res = await fetch(`${resolved}/system_stats`, { signal: AbortSignal.timeout(timeoutMs) }) - if (!res.ok) return { ok: false as const, host: resolved, status: res.status, stats: null } + if (!res.ok) return { ok: false as const, host: resolved, status: res.status, stats: null, timedOut: false } const stats = await res.json().catch(() => null) - return { ok: true as const, host: resolved, status: res.status, stats } - } catch { - return { ok: false as const, host: resolved, status: 0, stats: null } + return { ok: true as const, host: resolved, status: res.status, stats, timedOut: false } + } catch (error) { + const timedOut = error instanceof Error && (error.name === 'TimeoutError' || error.name === 'AbortError' || /timeout/i.test(error.message)) + return { ok: false as const, host: resolved, status: 0, stats: null, timedOut } } } @@ -173,6 +174,18 @@ async function ensureUnlocked(onStatus: StatusFn) { onStatus({ state: 'online', message: 'Image ComfyUI online', host }) return } + if (health.timedOut) { + log('http-busy', { host, timeoutMs: cfg.healthTimeoutMs }) + onStatus({ + state: 'busy', + message: 'Image ComfyUI is loaded but slow to answer. Not starting another instance.', + host, + processRunning: true + }) + await waitWhileBusy(onStatus) + onStatus({ state: 'online', message: 'Image ComfyUI online', host, processRunning: true }) + return + } const remote = await controlRequest('/status') if (remote?.http && remote.proxyPort) {