Retry library pulls after Comfy finishes and fall back to disk.
Long jobs were succeeding on Beast then failing the save step when /view briefly dropped; retries plus host-agent file serving keep finished MP4s from being orphaned. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+51
-7
@@ -19,7 +19,7 @@ function classifyError(message: string) {
|
||||
if (lower.includes('out of memory') || (lower.includes('cuda') && lower.includes('alloc')) || lower.includes('vram')) {
|
||||
return 'ComfyUI VRAM allocation failed. Try Turbo or a smaller aspect ratio.'
|
||||
}
|
||||
if (lower.includes('econnrefused') || lower.includes('unreachable') || lower.includes('fetch failed')) {
|
||||
if (lower.includes('econnrefused') || lower.includes('unreachable') || lower.includes('fetch failed') || lower.includes('connection dropped')) {
|
||||
return 'ComfyUI host connection dropped. Confirm the desktop instance is running and reachable on the LAN.'
|
||||
}
|
||||
if (lower.includes('timeout')) {
|
||||
@@ -28,6 +28,17 @@ function classifyError(message: string) {
|
||||
return message
|
||||
}
|
||||
|
||||
function errorText(error: unknown) {
|
||||
if (!error) return 'Unknown error'
|
||||
if (typeof error === 'object') {
|
||||
const rec = error as { statusMessage?: string; message?: string; data?: { cause?: string } }
|
||||
const bits = [rec.statusMessage, rec.message, rec.data?.cause].filter(Boolean)
|
||||
if (bits.length) return String(bits[0])
|
||||
}
|
||||
if (error instanceof Error) return error.message
|
||||
return String(error)
|
||||
}
|
||||
|
||||
function sleep(ms: number) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms))
|
||||
}
|
||||
@@ -175,8 +186,23 @@ export function watchComfyJob(job: Job, options: { persist?: boolean } = {}): Pr
|
||||
finishing = true
|
||||
job.saving = true
|
||||
try {
|
||||
const history = await fetchHistory(job.promptId)
|
||||
const video = extractVideo(history, job.promptId)
|
||||
let history: Awaited<ReturnType<typeof fetchHistory>> | null = null
|
||||
let video: ReturnType<typeof extractVideo> = null
|
||||
for (let attempt = 1; attempt <= 6; attempt++) {
|
||||
try {
|
||||
history = await fetchHistory(job.promptId)
|
||||
video = extractVideo(history, job.promptId)
|
||||
if (video) break
|
||||
} catch (error) {
|
||||
if (attempt >= 6) throw error
|
||||
}
|
||||
emitLocal({
|
||||
type: 'status',
|
||||
message: `Waiting for ComfyUI history (${attempt}/6)...`,
|
||||
progress: 96
|
||||
})
|
||||
await sleep(1000 * attempt)
|
||||
}
|
||||
if (!video) {
|
||||
finishing = false
|
||||
job.saving = false
|
||||
@@ -312,12 +338,20 @@ export function watchComfyJob(job: Job, options: { persist?: boolean } = {}): Pr
|
||||
} catch (saveError) {
|
||||
job.saving = false
|
||||
removeExtendTemp(job.library?.extendTmpDir)
|
||||
const message = saveError instanceof Error ? saveError.message : String(saveError)
|
||||
const message = classifyError(errorText(saveError))
|
||||
job.status = 'error'
|
||||
job.error = persist
|
||||
? `Video generated but library save failed: ${message}`
|
||||
: `Segment finished but could not be prepared: ${message}`
|
||||
emitChainJob(job, { type: 'error', error: job.error, message: job.error })
|
||||
// Keep pending so a later Recover / container restart can still pull the MP4.
|
||||
if (job.library && job.promptId) {
|
||||
writePendingJob(pendingFromJob(job, {
|
||||
promptId: job.promptId,
|
||||
currentClipId: job.clipId || job.library.parentClipId
|
||||
}))
|
||||
}
|
||||
await syncQueueFromJob(job).catch(() => null)
|
||||
}
|
||||
resolve()
|
||||
return true
|
||||
@@ -406,9 +440,19 @@ export function watchComfyJob(job: Job, options: { persist?: boolean } = {}): Pr
|
||||
if (payload.type === 'executing') {
|
||||
const node = data.node === null || data.node === undefined ? null : String(data.node)
|
||||
if (node === null) {
|
||||
const saved = await succeed()
|
||||
if (!saved) {
|
||||
emitLocal({ type: 'status', message: 'Waiting for ComfyUI to save the MP4...', progress: 96 })
|
||||
try {
|
||||
const saved = await succeed()
|
||||
if (!saved) {
|
||||
emitLocal({ type: 'status', message: 'Waiting for ComfyUI to save the MP4...', progress: 96 })
|
||||
}
|
||||
} catch (error) {
|
||||
finishing = false
|
||||
job.saving = false
|
||||
emitLocal({
|
||||
type: 'status',
|
||||
message: `Save hiccup (${errorText(error)}). Retrying...`,
|
||||
progress: 96
|
||||
})
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user