Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions src/context/ExecutionContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ export function ExecutionProvider({ children }: ExecutionProviderProps) {

const engineRef = useRef(createExecutionEngine())

// Use ref for execution state to avoid stale closures in rapid calls
const isExecutingRef = useRef(false)

// Debounce cooldown period (ms) to prevent rapid re-execution
const DEBOUNCE_COOLDOWN_MS = 300
const lastExecutionTimeRef = useRef(0)

const execute = useCallback(async () => {
if (!graph) {
console.error('No graph available for execution')
Expand All @@ -59,6 +66,20 @@ export function ExecutionProvider({ children }: ExecutionProviderProps) {
return
}

// Debounce: prevent execution if already running
if (isExecutingRef.current) {
console.log('Execution already in progress, ignoring request')
return
}

// Debounce: prevent rapid re-execution after completion
const now = Date.now()
if (now - lastExecutionTimeRef.current < DEBOUNCE_COOLDOWN_MS) {
console.log('Execution cooldown active, ignoring request')
return
}

isExecutingRef.current = true
setIsExecuting(true)
setProgress(0)
executionResults.clear()
Expand Down Expand Up @@ -100,6 +121,8 @@ export function ExecutionProvider({ children }: ExecutionProviderProps) {
} catch (error) {
console.error('Execution failed:', error)
} finally {
isExecutingRef.current = false
lastExecutionTimeRef.current = Date.now()
setIsExecuting(false)
setCurrentNodeId(null)
}
Expand All @@ -115,6 +138,20 @@ export function ExecutionProvider({ children }: ExecutionProviderProps) {
return
}

// Debounce: prevent execution if already running
if (isExecutingRef.current) {
console.log('Execution already in progress, ignoring request')
return
}

// Debounce: prevent rapid re-execution after completion
const now = Date.now()
if (now - lastExecutionTimeRef.current < DEBOUNCE_COOLDOWN_MS) {
console.log('Execution cooldown active, ignoring request')
return
}

isExecutingRef.current = true
setIsExecuting(true)
setProgress(0)
// Don't clear previous results - we'll use them for upstream nodes
Expand Down Expand Up @@ -152,6 +189,8 @@ export function ExecutionProvider({ children }: ExecutionProviderProps) {
} catch (error) {
console.error('Execution failed:', error)
} finally {
isExecutingRef.current = false
lastExecutionTimeRef.current = Date.now()
setIsExecuting(false)
setCurrentNodeId(null)
}
Expand All @@ -166,6 +205,20 @@ export function ExecutionProvider({ children }: ExecutionProviderProps) {
return
}

// Debounce: prevent execution if already running
if (isExecutingRef.current) {
console.log('Execution already in progress, ignoring request')
return
}

// Debounce: prevent rapid re-execution after completion
const now = Date.now()
if (now - lastExecutionTimeRef.current < DEBOUNCE_COOLDOWN_MS) {
console.log('Execution cooldown active, ignoring request')
return
}

isExecutingRef.current = true
setIsExecuting(true)
setProgress(0)
setNodeStatuses(new Map())
Expand Down Expand Up @@ -202,13 +255,17 @@ export function ExecutionProvider({ children }: ExecutionProviderProps) {
} catch (error) {
console.error('Execution failed:', error)
} finally {
isExecutingRef.current = false
lastExecutionTimeRef.current = Date.now()
setIsExecuting(false)
setCurrentNodeId(null)
}
}, [graph, canvas, executionResults, executionErrors])

const cancel = useCallback(() => {
engineRef.current.cancel()
isExecutingRef.current = false
lastExecutionTimeRef.current = Date.now()
setIsExecuting(false)
setCurrentNodeId(null)
console.log('Execution cancelled')
Expand Down