mirror of
https://github.com/langgenius/dify.git
synced 2026-09-08 11:04:27 +08:00
fix: display workflow run errors in the result panel (#39746)
(cherry picked from commit 54aced9e20)
This commit is contained in:
parent
1714d9b3a0
commit
7fdbeba468
@ -124,13 +124,15 @@ describe('useWorkflowRun callbacks helpers', () => {
|
||||
expect(fetchInspectVars).toHaveBeenCalledWith({})
|
||||
expect(invalidAllLastRun).toHaveBeenCalled()
|
||||
|
||||
callbacks.onError?.({ error: 'failed', node_type: 'llm' } as never)
|
||||
callbacks.onError?.('LLM provider and model are required.')
|
||||
expect(clearAbortController).toHaveBeenCalled()
|
||||
expect(handlers.handleWorkflowFailed).toHaveBeenCalled()
|
||||
expect(handlers.handleWorkflowFailed).toHaveBeenCalledWith(
|
||||
'LLM provider and model are required.',
|
||||
)
|
||||
expect(userOnError).toHaveBeenCalled()
|
||||
expect(getWorkflowRunningData).toHaveBeenCalled()
|
||||
expect(trackWorkflowRunFailed).toHaveBeenCalledWith(
|
||||
{ error: 'failed', node_type: 'llm' },
|
||||
'LLM provider and model are required.',
|
||||
workflowData,
|
||||
)
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ type ContainerSize = {
|
||||
type WorkflowRunEventHandlers = {
|
||||
handleWorkflowStarted: NonNullable<IOtherOptions['onWorkflowStarted']>
|
||||
handleWorkflowFinished: NonNullable<IOtherOptions['onWorkflowFinished']>
|
||||
handleWorkflowFailed: () => void
|
||||
handleWorkflowFailed: (error?: string) => void
|
||||
handleWorkflowNodeStarted: (
|
||||
params: Parameters<NonNullable<IOtherOptions['onNodeStarted']>>[0],
|
||||
containerParams: ContainerSize,
|
||||
@ -150,7 +150,7 @@ export const createBaseWorkflowRunCallbacks = ({
|
||||
|
||||
const wrappedOnError: IOtherOptions['onError'] = (params, code) => {
|
||||
clearAbortController()
|
||||
handleWorkflowFailed()
|
||||
handleWorkflowFailed(params)
|
||||
const workflowData = getWorkflowRunningData()
|
||||
invalidateRunHistory(runHistoryUrl)
|
||||
clearListeningState()
|
||||
@ -358,7 +358,7 @@ export const createFinalWorkflowRunCallbacks = ({
|
||||
},
|
||||
onError: (params, code) => {
|
||||
clearAbortController()
|
||||
handleWorkflowFailed()
|
||||
handleWorkflowFailed(params)
|
||||
const workflowData = getWorkflowRunningData()
|
||||
invalidateRunHistory(runHistoryUrl)
|
||||
clearListeningState()
|
||||
|
||||
@ -66,10 +66,13 @@ describe('useWorkflowFailed', () => {
|
||||
})
|
||||
|
||||
act(() => {
|
||||
result.current.handleWorkflowFailed()
|
||||
result.current.handleWorkflowFailed('LLM provider and model are required.')
|
||||
})
|
||||
|
||||
expect(store.getState().workflowRunningData!.result.status).toBe(WorkflowRunningStatus.Failed)
|
||||
expect(store.getState().workflowRunningData!.result.error).toBe(
|
||||
'LLM provider and model are required.',
|
||||
)
|
||||
expect(store.getState().workflowRunningData!.tracing!.map((trace) => trace.status)).toEqual([
|
||||
NodeRunningStatus.Failed,
|
||||
NodeRunningStatus.Succeeded,
|
||||
@ -115,4 +118,44 @@ describe('useWorkflowFailed', () => {
|
||||
|
||||
expect(store.getState().workflowRunningData!.result.status).toBe(WorkflowRunningStatus.Stopped)
|
||||
})
|
||||
|
||||
it('adds a late error message to an already failed workflow', () => {
|
||||
const { result, store } = renderRunEventHook(() => useWorkflowFailed(), {
|
||||
initialStoreState: {
|
||||
workflowRunningData: baseRunningData({
|
||||
result: { status: WorkflowRunningStatus.Failed },
|
||||
}),
|
||||
},
|
||||
})
|
||||
|
||||
act(() => {
|
||||
result.current.handleWorkflowFailed('LLM provider and model are required.')
|
||||
})
|
||||
|
||||
expect(store.getState().workflowRunningData!.result).toMatchObject({
|
||||
status: WorkflowRunningStatus.Failed,
|
||||
error: 'LLM provider and model are required.',
|
||||
})
|
||||
})
|
||||
|
||||
it('keeps the workflow_finished error when a generic error arrives later', () => {
|
||||
const { result, store } = renderRunEventHook(() => useWorkflowFailed(), {
|
||||
initialStoreState: {
|
||||
workflowRunningData: baseRunningData({
|
||||
result: {
|
||||
status: WorkflowRunningStatus.Failed,
|
||||
error: 'LLM provider and model are required.',
|
||||
},
|
||||
}),
|
||||
},
|
||||
})
|
||||
|
||||
act(() => {
|
||||
result.current.handleWorkflowFailed('Server Error')
|
||||
})
|
||||
|
||||
expect(store.getState().workflowRunningData!.result.error).toBe(
|
||||
'LLM provider and model are required.',
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@ -8,52 +8,66 @@ export const useWorkflowFailed = () => {
|
||||
const store = useStoreApi()
|
||||
const workflowStore = useWorkflowStore()
|
||||
|
||||
const handleWorkflowFailed = useCallback(() => {
|
||||
const { workflowRunningData, setWorkflowRunningData } = workflowStore.getState()
|
||||
if (!workflowRunningData) return
|
||||
if (
|
||||
workflowRunningData.result.status === WorkflowRunningStatus.Succeeded ||
|
||||
workflowRunningData.result.status === WorkflowRunningStatus.Failed ||
|
||||
workflowRunningData.result.status === WorkflowRunningStatus.Stopped
|
||||
)
|
||||
return
|
||||
const handleWorkflowFailed = useCallback(
|
||||
(error?: string) => {
|
||||
const { workflowRunningData, setWorkflowRunningData } = workflowStore.getState()
|
||||
if (!workflowRunningData) return
|
||||
if (
|
||||
workflowRunningData.result.status === WorkflowRunningStatus.Succeeded ||
|
||||
workflowRunningData.result.status === WorkflowRunningStatus.Stopped
|
||||
)
|
||||
return
|
||||
|
||||
const { getNodes, setNodes, edges, setEdges } = store.getState()
|
||||
if (workflowRunningData.result.status === WorkflowRunningStatus.Failed) {
|
||||
if (!error || workflowRunningData.result.error) return
|
||||
|
||||
setWorkflowRunningData(
|
||||
produce(workflowRunningData, (draft) => {
|
||||
draft.result = {
|
||||
...draft.result,
|
||||
status: WorkflowRunningStatus.Failed,
|
||||
}
|
||||
draft.tracing?.forEach((trace) => {
|
||||
if (trace.status === NodeRunningStatus.Running) trace.status = NodeRunningStatus.Failed
|
||||
})
|
||||
}),
|
||||
)
|
||||
setWorkflowRunningData(
|
||||
produce(workflowRunningData, (draft) => {
|
||||
draft.result.error = error
|
||||
}),
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
setNodes(
|
||||
produce(getNodes(), (draft) => {
|
||||
draft.forEach((node) => {
|
||||
if (node.data._runningStatus === NodeRunningStatus.Running)
|
||||
node.data._runningStatus = NodeRunningStatus.Failed
|
||||
node.data._waitingRun = false
|
||||
})
|
||||
}),
|
||||
)
|
||||
setEdges(
|
||||
produce(edges, (draft) => {
|
||||
draft.forEach((edge) => {
|
||||
if (!edge.data) return
|
||||
if (edge.data._sourceRunningStatus === NodeRunningStatus.Running)
|
||||
edge.data._sourceRunningStatus = NodeRunningStatus.Failed
|
||||
if (edge.data._targetRunningStatus === NodeRunningStatus.Running)
|
||||
edge.data._targetRunningStatus = NodeRunningStatus.Failed
|
||||
edge.data._waitingRun = false
|
||||
})
|
||||
}),
|
||||
)
|
||||
}, [store, workflowStore])
|
||||
const { getNodes, setNodes, edges, setEdges } = store.getState()
|
||||
|
||||
setWorkflowRunningData(
|
||||
produce(workflowRunningData, (draft) => {
|
||||
draft.result = {
|
||||
...draft.result,
|
||||
status: WorkflowRunningStatus.Failed,
|
||||
error,
|
||||
}
|
||||
draft.tracing?.forEach((trace) => {
|
||||
if (trace.status === NodeRunningStatus.Running) trace.status = NodeRunningStatus.Failed
|
||||
})
|
||||
}),
|
||||
)
|
||||
|
||||
setNodes(
|
||||
produce(getNodes(), (draft) => {
|
||||
draft.forEach((node) => {
|
||||
if (node.data._runningStatus === NodeRunningStatus.Running)
|
||||
node.data._runningStatus = NodeRunningStatus.Failed
|
||||
node.data._waitingRun = false
|
||||
})
|
||||
}),
|
||||
)
|
||||
setEdges(
|
||||
produce(edges, (draft) => {
|
||||
draft.forEach((edge) => {
|
||||
if (!edge.data) return
|
||||
if (edge.data._sourceRunningStatus === NodeRunningStatus.Running)
|
||||
edge.data._sourceRunningStatus = NodeRunningStatus.Failed
|
||||
if (edge.data._targetRunningStatus === NodeRunningStatus.Running)
|
||||
edge.data._targetRunningStatus = NodeRunningStatus.Failed
|
||||
edge.data._waitingRun = false
|
||||
})
|
||||
}),
|
||||
)
|
||||
},
|
||||
[store, workflowStore],
|
||||
)
|
||||
|
||||
return {
|
||||
handleWorkflowFailed,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user