fix: serialize workflow draft sync operations (#27487)

This commit is contained in:
lyzno1 2025-10-27 13:29:40 +08:00 committed by GitHub
parent d705fece9d
commit 440262a51b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 33 additions and 4 deletions

View File

@ -7,6 +7,7 @@ import {
import {
useNodesReadOnly,
} from '@/app/components/workflow/hooks/use-workflow'
import { useSerialAsyncCallback } from '@/app/components/workflow/hooks/use-serial-async-callback'
import { API_PREFIX } from '@/config'
import { syncWorkflowDraft } from '@/service/workflow'
import { usePipelineRefreshDraft } from '.'
@ -83,7 +84,7 @@ export const useNodesSyncDraft = () => {
}
}, [getPostParams, getNodesReadOnly])
const doSyncWorkflowDraft = useCallback(async (
const performSync = useCallback(async (
notRefreshWhenSyncError?: boolean,
callback?: {
onSuccess?: () => void
@ -121,6 +122,8 @@ export const useNodesSyncDraft = () => {
}
}, [getPostParams, getNodesReadOnly, workflowStore, handleRefreshWorkflowDraft])
const doSyncWorkflowDraft = useSerialAsyncCallback(performSync, getNodesReadOnly)
return {
doSyncWorkflowDraft,
syncWorkflowDraftWhenPageClose,

View File

@ -3,6 +3,7 @@ import { produce } from 'immer'
import { useStoreApi } from 'reactflow'
import { useWorkflowStore } from '@/app/components/workflow/store'
import { useNodesReadOnly } from '@/app/components/workflow/hooks/use-workflow'
import { useSerialAsyncCallback } from '@/app/components/workflow/hooks/use-serial-async-callback'
import { syncWorkflowDraft } from '@/service/workflow'
import { useFeaturesStore } from '@/app/components/base/features/hooks'
import { API_PREFIX } from '@/config'
@ -87,7 +88,7 @@ export const useNodesSyncDraft = () => {
navigator.sendBeacon(`${API_PREFIX}${postParams.url}`, JSON.stringify(postParams.params))
}, [getPostParams, getNodesReadOnly])
const doSyncWorkflowDraft = useCallback(async (
const performSync = useCallback(async (
notRefreshWhenSyncError?: boolean,
callback?: {
onSuccess?: () => void
@ -125,6 +126,8 @@ export const useNodesSyncDraft = () => {
}
}, [workflowStore, getPostParams, getNodesReadOnly, handleRefreshWorkflowDraft])
const doSyncWorkflowDraft = useSerialAsyncCallback(performSync, getNodesReadOnly)
return {
doSyncWorkflowDraft,
syncWorkflowDraftWhenPageClose,

View File

@ -23,3 +23,4 @@ export * from './use-inspect-vars-crud'
export * from './use-set-workflow-vars-with-value'
export * from './use-workflow-search'
export * from './use-auto-generate-webhook-url'
export * from './use-serial-async-callback'

View File

@ -0,0 +1,22 @@
import {
useCallback,
useRef,
} from 'react'
export const useSerialAsyncCallback = <Args extends any[], Result = void>(
fn: (...args: Args) => Promise<Result> | Result,
shouldSkip?: () => boolean,
) => {
const queueRef = useRef<Promise<unknown>>(Promise.resolve())
return useCallback((...args: Args) => {
if (shouldSkip?.())
return Promise.resolve(undefined as Result)
const lastPromise = queueRef.current.catch(() => undefined)
const nextPromise = lastPromise.then(() => fn(...args))
queueRef.current = nextPromise
return nextPromise
}, [fn, shouldSkip])
}

View File

@ -523,14 +523,14 @@ export const useNodesReadOnly = () => {
const historyWorkflowData = useStore(s => s.historyWorkflowData)
const isRestoring = useStore(s => s.isRestoring)
const getNodesReadOnly = useCallback(() => {
const getNodesReadOnly = useCallback((): boolean => {
const {
workflowRunningData,
historyWorkflowData,
isRestoring,
} = workflowStore.getState()
return workflowRunningData?.result.status === WorkflowRunningStatus.Running || historyWorkflowData || isRestoring
return !!(workflowRunningData?.result.status === WorkflowRunningStatus.Running || historyWorkflowData || isRestoring)
}, [workflowStore])
return {