Skip to content

Commit 833825f

Browse files
fix(deploy-check): race condition fixes (#2710)
1 parent 261becd commit 833825f

File tree

3 files changed

+24
-46
lines changed

3 files changed

+24
-46
lines changed

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/deploy.tsx

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use client'
22

3-
import { useCallback, useState } from 'react'
3+
import { useState } from 'react'
44
import { Loader2 } from 'lucide-react'
55
import { Button, Tooltip } from '@/components/emcn'
66
import { DeployModal } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/components/deploy-modal/deploy-modal'
@@ -62,26 +62,13 @@ export function Deploy({ activeWorkflowId, userPermissions, className }: DeployP
6262
const canDeploy = userPermissions.canAdmin
6363
const isDisabled = isDeploying || !canDeploy || isEmpty
6464

65-
/**
66-
* Handle deploy button click
67-
*/
68-
const onDeployClick = useCallback(async () => {
65+
const onDeployClick = async () => {
6966
if (!canDeploy || !activeWorkflowId) return
7067

7168
const result = await handleDeployClick()
7269
if (result.shouldOpenModal) {
7370
setIsModalOpen(true)
7471
}
75-
}, [canDeploy, activeWorkflowId, handleDeployClick])
76-
77-
const refetchWithErrorHandling = async () => {
78-
if (!activeWorkflowId) return
79-
80-
try {
81-
await refetchDeployedState()
82-
} catch (error) {
83-
// Error already logged in hook
84-
}
8572
}
8673

8774
/**
@@ -135,7 +122,7 @@ export function Deploy({ activeWorkflowId, userPermissions, className }: DeployP
135122
needsRedeployment={changeDetected}
136123
deployedState={deployedState!}
137124
isLoadingDeployedState={isLoadingDeployedState}
138-
refetchDeployedState={refetchWithErrorHandling}
125+
refetchDeployedState={refetchDeployedState}
139126
/>
140127
</>
141128
)

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/hooks/use-change-detection.ts

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { useMemo } from 'react'
22
import { hasWorkflowChanged } from '@/lib/workflows/comparison'
3-
import { useDebounce } from '@/hooks/use-debounce'
43
import { useVariablesStore } from '@/stores/panel/variables/store'
54
import { useSubBlockStore } from '@/stores/workflows/subblock/store'
65
import { useWorkflowStore } from '@/stores/workflows/workflow/store'
@@ -48,16 +47,12 @@ export function useChangeDetection({
4847
const blockSubValues = subBlockValues?.[blockId] || {}
4948
const subBlocks: Record<string, any> = {}
5049

51-
for (const [subId, value] of Object.entries(blockSubValues)) {
52-
subBlocks[subId] = { value }
53-
}
54-
5550
if (block.subBlocks) {
5651
for (const [subId, subBlock] of Object.entries(block.subBlocks)) {
57-
if (!subBlocks[subId]) {
58-
subBlocks[subId] = subBlock
59-
} else {
60-
subBlocks[subId] = { ...subBlock, value: subBlocks[subId].value }
52+
const storedValue = blockSubValues[subId]
53+
subBlocks[subId] = {
54+
...subBlock,
55+
value: storedValue !== undefined ? storedValue : subBlock.value,
6156
}
6257
}
6358
}
@@ -77,14 +72,12 @@ export function useChangeDetection({
7772
} as WorkflowState & { variables: Record<string, any> }
7873
}, [workflowId, blocks, edges, loops, parallels, subBlockValues, workflowVariables])
7974

80-
const rawChangeDetected = useMemo(() => {
75+
const changeDetected = useMemo(() => {
8176
if (!currentState || !deployedState || isLoadingDeployedState) {
8277
return false
8378
}
8479
return hasWorkflowChanged(currentState, deployedState)
8580
}, [currentState, deployedState, isLoadingDeployedState])
8681

87-
const changeDetected = useDebounce(rawChangeDetected, 300)
88-
8982
return { changeDetected }
9083
}

apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/deploy/hooks/use-deployed-state.ts

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect, useState } from 'react'
1+
import { useCallback, useEffect, useState } from 'react'
22
import { createLogger } from '@sim/logger'
33
import { useWorkflowRegistry } from '@/stores/workflows/registry/store'
44
import type { WorkflowState } from '@/stores/workflows/workflow/types'
@@ -27,29 +27,27 @@ export function useDeployedState({
2727
(state) => state.setWorkflowNeedsRedeployment
2828
)
2929

30-
/**
31-
* Fetches the deployed state of the workflow from the server
32-
* This is the single source of truth for deployed workflow state
33-
*/
34-
const fetchDeployedState = async () => {
35-
if (!workflowId || !isDeployed) {
30+
const fetchDeployedState = useCallback(async () => {
31+
const registry = useWorkflowRegistry.getState()
32+
const currentWorkflowId = registry.activeWorkflowId
33+
const deploymentStatus = currentWorkflowId
34+
? registry.getWorkflowDeploymentStatus(currentWorkflowId)
35+
: null
36+
const currentIsDeployed = deploymentStatus?.isDeployed ?? false
37+
38+
if (!currentWorkflowId || !currentIsDeployed) {
3639
setDeployedState(null)
3740
return
3841
}
3942

40-
// Store the workflow ID at the start of the request to prevent race conditions
41-
const requestWorkflowId = workflowId
42-
43-
// Helper to get current active workflow ID for race condition checks
44-
const getCurrentActiveWorkflowId = () => useWorkflowRegistry.getState().activeWorkflowId
43+
const requestWorkflowId = currentWorkflowId
4544

4645
try {
4746
setIsLoadingDeployedState(true)
4847

4948
const response = await fetch(`/api/workflows/${requestWorkflowId}/deployed`)
5049

51-
// Check if the workflow ID changed during the request (user navigated away)
52-
if (requestWorkflowId !== getCurrentActiveWorkflowId()) {
50+
if (requestWorkflowId !== useWorkflowRegistry.getState().activeWorkflowId) {
5351
logger.debug('Workflow changed during deployed state fetch, ignoring response')
5452
return
5553
}
@@ -64,22 +62,22 @@ export function useDeployedState({
6462

6563
const data = await response.json()
6664

67-
if (requestWorkflowId === getCurrentActiveWorkflowId()) {
65+
if (requestWorkflowId === useWorkflowRegistry.getState().activeWorkflowId) {
6866
setDeployedState(data.deployedState || null)
6967
} else {
7068
logger.debug('Workflow changed after deployed state response, ignoring result')
7169
}
7270
} catch (error) {
7371
logger.error('Error fetching deployed state:', { error })
74-
if (requestWorkflowId === getCurrentActiveWorkflowId()) {
72+
if (requestWorkflowId === useWorkflowRegistry.getState().activeWorkflowId) {
7573
setDeployedState(null)
7674
}
7775
} finally {
78-
if (requestWorkflowId === getCurrentActiveWorkflowId()) {
76+
if (requestWorkflowId === useWorkflowRegistry.getState().activeWorkflowId) {
7977
setIsLoadingDeployedState(false)
8078
}
8179
}
82-
}
80+
}, [])
8381

8482
useEffect(() => {
8583
if (!workflowId) {

0 commit comments

Comments
 (0)