Fix Comfy wake: launch when HTTP is down instead of treating leftover Python as already booting.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Towsty
2026-09-02 07:58:50 -05:00
co-authored by Cursor
parent aa2cefbcf2
commit 2ae5f6fb2e
3 changed files with 28 additions and 17 deletions
+23 -12
View File
@@ -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 })
}
+2 -2
View File
@@ -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 })
+3 -3
View File
@@ -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 }