mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-02-20 14:54:12 +00:00
fix: jobs stuck in initializing state when failing before execution_start (#8689)
## Summary Fix jobs getting permanently stuck in "initializing" state when they fail before the `execution_start` WebSocket event fires. ## Changes - **What**: Added `reconcileInitializingPrompts(activeJobIds)` to `executionStore` that removes orphaned initializing prompt IDs not present in the active jobs set. Called from `queueStore.update()` after fetching Running/Pending jobs, ensuring stale initializing states are cleaned up on every queue poll. ## Review Focus - The reconciliation delegates to the existing `clearInitializationByPromptIds` to avoid duplicating Set-diffing logic. - Only runs during `queueStore.update()` which is already a periodic poll — no additional network calls. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-8689-fix-jobs-stuck-in-initializing-state-when-failing-before-execution_start-2ff6d73d3650814dbeeeda71c8bb7d43) by [Unito](https://www.unito.io)
This commit is contained in:
@@ -132,6 +132,48 @@ describe('useExecutionStore - NodeLocatorId conversions', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('useExecutionStore - reconcileInitializingPrompts', () => {
|
||||
let store: ReturnType<typeof useExecutionStore>
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
setActivePinia(createTestingPinia({ stubActions: false }))
|
||||
store = useExecutionStore()
|
||||
})
|
||||
|
||||
it('should remove prompt IDs not present in active jobs', () => {
|
||||
store.initializingPromptIds = new Set(['job-1', 'job-2', 'job-3'])
|
||||
|
||||
store.reconcileInitializingPrompts(new Set(['job-1']))
|
||||
|
||||
expect(store.initializingPromptIds).toEqual(new Set(['job-1']))
|
||||
})
|
||||
|
||||
it('should be a no-op when all initializing IDs are active', () => {
|
||||
store.initializingPromptIds = new Set(['job-1', 'job-2'])
|
||||
|
||||
store.reconcileInitializingPrompts(new Set(['job-1', 'job-2', 'job-3']))
|
||||
|
||||
expect(store.initializingPromptIds).toEqual(new Set(['job-1', 'job-2']))
|
||||
})
|
||||
|
||||
it('should be a no-op when there are no initializing prompts', () => {
|
||||
store.initializingPromptIds = new Set()
|
||||
|
||||
store.reconcileInitializingPrompts(new Set(['job-1']))
|
||||
|
||||
expect(store.initializingPromptIds).toEqual(new Set())
|
||||
})
|
||||
|
||||
it('should clear all initializing IDs when no active jobs exist', () => {
|
||||
store.initializingPromptIds = new Set(['job-1', 'job-2'])
|
||||
|
||||
store.reconcileInitializingPrompts(new Set())
|
||||
|
||||
expect(store.initializingPromptIds).toEqual(new Set())
|
||||
})
|
||||
})
|
||||
|
||||
describe('useExecutionStore - Node Error Lookups', () => {
|
||||
let store: ReturnType<typeof useExecutionStore>
|
||||
|
||||
|
||||
@@ -442,6 +442,13 @@ export const useExecutionStore = defineStore('execution', () => {
|
||||
initializingPromptIds.value = next
|
||||
}
|
||||
|
||||
function reconcileInitializingPrompts(activeJobIds: Set<string>) {
|
||||
const orphaned = [...initializingPromptIds.value].filter(
|
||||
(id) => !activeJobIds.has(id)
|
||||
)
|
||||
clearInitializationByPromptIds(orphaned)
|
||||
}
|
||||
|
||||
function isPromptInitializing(
|
||||
promptId: string | number | undefined
|
||||
): boolean {
|
||||
@@ -716,6 +723,7 @@ export const useExecutionStore = defineStore('execution', () => {
|
||||
isPromptInitializing,
|
||||
clearInitializationByPromptId,
|
||||
clearInitializationByPromptIds,
|
||||
reconcileInitializingPrompts,
|
||||
bindExecutionEvents,
|
||||
unbindExecutionEvents,
|
||||
storePrompt,
|
||||
|
||||
@@ -537,6 +537,18 @@ export const useQueueStore = defineStore('queue', () => {
|
||||
}
|
||||
})
|
||||
|
||||
// Only reconcile when the queue fetch returned data. api.getQueue()
|
||||
// returns empty Running/Pending on transient errors, which would
|
||||
// incorrectly clear all initializing prompts.
|
||||
const queueHasData = queue.Running.length > 0 || queue.Pending.length > 0
|
||||
if (queueHasData) {
|
||||
const activeJobIds = new Set([
|
||||
...queue.Running.map((j) => j.id),
|
||||
...queue.Pending.map((j) => j.id)
|
||||
])
|
||||
executionStore.reconcileInitializingPrompts(activeJobIds)
|
||||
}
|
||||
|
||||
// Sort by create_time descending and limit to maxItems
|
||||
const sortedHistory = [...history]
|
||||
.sort((a, b) => b.create_time - a.create_time)
|
||||
|
||||
Reference in New Issue
Block a user