From 2ae5f6fb2ec2f41554d8e22f7e887683d4fc7f45 Mon Sep 17 00:00:00 2001 From: Towsty Date: Wed, 2 Sep 2026 07:58:50 -0500 Subject: [PATCH] Fix Comfy wake: launch when HTTP is down instead of treating leftover Python as already booting. Co-authored-by: Cursor --- scripts/comfy-host-agent.mjs | 35 +++++++++++++++++++---------- server/utils/comfyLifecycle.ts | 4 ++-- server/utils/imageComfyLifecycle.ts | 6 ++--- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/scripts/comfy-host-agent.mjs b/scripts/comfy-host-agent.mjs index 267033c..00beec0 100644 --- a/scripts/comfy-host-agent.mjs +++ b/scripts/comfy-host-agent.mjs @@ -16,6 +16,7 @@ const trainingUrl = String(process.env.TRAINING_CONTROL_URL || 'http://127.0.0.1 let lastWorkAt = Date.now() let lastQueueRunning = 0 +let lastLaunchAt = 0 let stoppedByAgent = false let lastHealthyPort = 0 let lastProcessUp = false @@ -162,12 +163,23 @@ function ensureProxy(targetPort) { }) } +function markAsleep() { + stoppedByAgent = true + lastQueueRunning = 0 + lastHealthyPort = 0 + lastProcessUp = false + lastLaunchAt = 0 + proxyTarget = 0 +} + async function syncProxy() { const healthyPort = await findHealthyPort() lastHealthyPort = healthyPort || 0 if (healthyPort) { ensureProxy(healthyPort) lastProcessUp = true + } else { + lastProcessUp = false } return healthyPort } @@ -493,10 +505,7 @@ async function maybeIdleStop(healthyPort) { http: Boolean(healthyPort) })) const killed = await stopComfyProcesses() - stoppedByAgent = true - lastQueueRunning = 0 - lastHealthyPort = 0 - lastProcessUp = false + markAsleep() console.log(JSON.stringify({ src: 'comfy-host-agent', event: 'stopped', reason: 'idle', killed })) } @@ -617,14 +626,18 @@ const server = http.createServer(async (req, res) => { if (req.method === 'GET' && url.pathname === '/status') { // Answer immediately. MyMonitor allows ~500ms; probing ports + WMI here // made the A light stay red even while this process was running. - const healthyPort = lastHealthyPort || proxyTarget - const processUpNow = Boolean(lastProcessUp || healthyPort) + // Do not treat a stale proxyTarget as proof Comfy is up — that made + // /status report asleep+http at once, so training skipped /stop. + const healthyPort = lastHealthyPort || 0 + const processUpNow = Boolean(lastProcessUp && healthyPort) + const asleep = !healthyPort && !processUpNow + if (!asleep) stoppedByAgent = false return json(res, 200, { ok: true, http: Boolean(healthyPort), process: processUpNow, processUp: processUpNow, - asleep: Boolean(stoppedByAgent || (!healthyPort && !processUpNow)), + asleep, lastActivityAt: new Date(lastWorkAt).toISOString(), idleMs, port: healthyPort || null, @@ -647,11 +660,12 @@ const server = http.createServer(async (req, res) => { markWork() return json(res, 200, { ok: true, started: false, already: true, asleep: false, port: healthyPort, proxyPort }) } - if (await pythonMainUp()) { + if (lastLaunchAt && Date.now() - lastLaunchAt < 60_000) { return json(res, 200, { ok: true, started: false, already: true, booting: true, asleep: false }) } await taskkillImage('Comfy Desktop.exe') stoppedByAgent = false + lastLaunchAt = Date.now() const launched = await startComfy() if (launched.port) { lastProcessUp = true @@ -671,10 +685,7 @@ const server = http.createServer(async (req, res) => { }) } const killed = await stopComfyProcesses() - stoppedByAgent = true - lastQueueRunning = 0 - lastHealthyPort = 0 - lastProcessUp = false + markAsleep() console.log(JSON.stringify({ src: 'comfy-host-agent', event: 'stopped', reason: 'stop', killed })) return json(res, 200, { ok: true, stopped: true, asleep: true, killed }) } diff --git a/server/utils/comfyLifecycle.ts b/server/utils/comfyLifecycle.ts index 9cb8b83..d28fc7a 100644 --- a/server/utils/comfyLifecycle.ts +++ b/server/utils/comfyLifecycle.ts @@ -154,7 +154,7 @@ export async function requestComfyWake() { statusMessage: 'COMFY_CONTROL_URL is not set. The studio cannot poke the Beast host agent.' }) } - const remote = await controlRequest('/start', 'POST') + const remote = await controlRequest('/start', 'POST', 25_000) if (!remote) { throw createError({ statusCode: 503, @@ -263,7 +263,7 @@ async function startComfy() { } lastStartAt = now - const remote = await controlRequest('/start', 'POST') + const remote = await controlRequest('/start', 'POST', 25_000) throwIfTrainingBusy(remote) if (remote?.ok || remote?.started) { log('start-remote', { pid: remote.pid || null }) diff --git a/server/utils/imageComfyLifecycle.ts b/server/utils/imageComfyLifecycle.ts index 83b7412..428e071 100644 --- a/server/utils/imageComfyLifecycle.ts +++ b/server/utils/imageComfyLifecycle.ts @@ -88,7 +88,7 @@ export async function fetchImageQueue() { return fetchQueueAt(getImageComfyHost()) } -async function controlRequest(path: string, method = 'GET') { +async function controlRequest(path: string, method = 'GET', timeoutMs = 5000) { const { controlUrl, controlToken } = settings() if (!controlUrl) return null try { @@ -98,7 +98,7 @@ async function controlRequest(path: string, method = 'GET') { Accept: 'application/json', ...(controlToken ? { Authorization: `Bearer ${controlToken}` } : {}) }, - signal: AbortSignal.timeout(5000) + signal: AbortSignal.timeout(timeoutMs) }) if (!res.ok) return { ok: false, status: res.status } return await res.json() as { @@ -154,7 +154,7 @@ async function startImageComfy() { return { started: false, reason: 'recent-start' as const } } lastStartAt = now - const remote = await controlRequest('/start', 'POST') + const remote = await controlRequest('/start', 'POST', 25_000) if (remote?.ok || remote?.started) { log('start-remote', { port: remote.port || null }) return { started: true, reason: 'remote' as const }