Add Force reset to clear stuck jobs and kill a wedged Comfy.

Settings and the header menu can cancel invisible queue/pending work and force-stop Beast when Sleep is blocked.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Towsty
2026-09-03 21:24:10 -05:00
co-authored by Cursor
parent ea66ed8e3d
commit 5df9e2d8ac
5 changed files with 194 additions and 16 deletions
+42 -4
View File
@@ -31,7 +31,7 @@
type="button"
class="rounded-xl border px-3 py-2 text-sm disabled:cursor-not-allowed disabled:opacity-60"
:class="gpuSleeping ? 'border-amber-300/40 text-amber-100' : 'border-white/15 text-zinc-200 hover:border-amber-300/50 hover:text-white'"
:disabled="gpuSleeping || gpuWaking"
:disabled="gpuSleeping || gpuWaking || gpuForceResetting"
@click="sleepGpu"
>
{{ gpuSleeping ? 'Stopping GPU…' : 'Sleep GPU' }}
@@ -40,12 +40,24 @@
type="button"
class="rounded-xl border px-3 py-2 text-sm disabled:cursor-not-allowed disabled:opacity-60"
:class="gpuWaking ? 'border-amber-300/40 text-amber-100' : 'border-amber-400/40 text-amber-200 hover:border-amber-300 hover:text-amber-50'"
:disabled="gpuWaking || gpuSleeping"
:disabled="gpuWaking || gpuSleeping || gpuForceResetting"
@click="wakeGpu"
>
{{ gpuWaking ? 'Starting GPU…' : 'Wake GPU' }}
</button>
<button
type="button"
class="rounded-xl border border-red-400/40 px-3 py-2 text-sm text-red-200 hover:border-red-300 hover:text-red-50 disabled:cursor-not-allowed disabled:opacity-60"
:disabled="gpuForceResetting || gpuSleeping || gpuWaking"
title="Cancel stuck Studio jobs, clear Comfy’s queue, and kill Comfy even if a job is wedged"
@click="forceResetGpu"
>
{{ gpuForceResetting ? 'Force resetting…' : 'Force reset GPU' }}
</button>
</div>
<p class="text-[11px] text-zinc-500">
Force reset: clears stuck/invisible queue jobs, interrupts Comfy, and kills it if Sleep is blocked. Does not shut the PC down.
</p>
<p v-if="gpuMessage" class="text-xs" :class="gpuError ? 'text-red-300' : 'text-zinc-500'">{{ gpuMessage }}</p>
</div>
<label class="mt-4 flex cursor-pointer items-center justify-between gap-3 rounded-2xl border border-white/10 bg-zinc-950/50 px-4 py-3 text-sm">
@@ -497,6 +509,7 @@ const storageLoading = ref(true)
const storageError = ref('')
const gpuSleeping = ref(false)
const gpuWaking = ref(false)
const gpuForceResetting = ref(false)
const gpuError = ref(false)
const gpuMessage = ref('')
const notifyComplete = ref(true)
@@ -688,7 +701,7 @@ function onDefaultVideoDuration(value: number) {
}
async function sleepGpu() {
if (gpuSleeping.value || gpuWaking.value) return
if (gpuSleeping.value || gpuWaking.value || gpuForceResetting.value) return
gpuSleeping.value = true
gpuError.value = false
gpuMessage.value = 'Stopping Comfy on the GPU…'
@@ -704,7 +717,7 @@ async function sleepGpu() {
}
async function wakeGpu() {
if (gpuWaking.value || gpuSleeping.value) return
if (gpuWaking.value || gpuSleeping.value || gpuForceResetting.value) return
gpuWaking.value = true
gpuError.value = false
gpuMessage.value = 'Starting Comfy on the GPU…'
@@ -719,6 +732,31 @@ async function wakeGpu() {
}
}
async function forceResetGpu() {
if (gpuForceResetting.value || gpuSleeping.value || gpuWaking.value) return
const ok = window.confirm(
'Force reset clears stuck Studio/queue jobs and kills Comfy even if a generation is wedged. Continue?'
)
if (!ok) return
gpuForceResetting.value = true
gpuError.value = false
gpuMessage.value = 'Force-resetting Comfy and clearing stuck jobs…'
try {
const result = await $fetch<{
message?: string
cleared?: { cancelledStudio?: number; clearedPending?: number; cancelledLive?: number }
}>('/api/comfy/force-reset', { method: 'POST' })
const c = result.cleared || {}
gpuMessage.value = result.message
|| `Cleared ${c.cancelledStudio || 0} queue job(s), ${c.clearedPending || 0} pending, ${c.cancelledLive || 0} live. Comfy is stopped — Wake when ready.`
} catch (error: any) {
gpuError.value = true
gpuMessage.value = error?.data?.statusMessage || error?.statusMessage || 'Could not force-reset Comfy.'
} finally {
gpuForceResetting.value = false
}
}
async function loadLoraKeys() {
loraRowsLoading.value = true
try {