Skip to content

Commit bcc53f3

Browse files
committed
fix tests
1 parent 233b307 commit bcc53f3

5 files changed

Lines changed: 44 additions & 7 deletions

File tree

apps/sim/app/api/workflows/[id]/deploy/route.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,15 @@ export const GET = withRouteHandler(
4848
return createErrorResponse(error.message, error.status)
4949
}
5050

51+
/**
52+
* A workflow is deployed only when an active version snapshot exists —
53+
* the same definition POST and the v1 routes use. The legacy
54+
* `workflow.isDeployed` flag is deliberately not consulted: when it
55+
* disagrees with the version table the workflow cannot actually serve
56+
* traffic, so reporting it as live would be untruthful.
57+
*/
5158
const deploymentSummary = await getWorkflowDeploymentSummary(id)
52-
const isDeployed = deploymentSummary.activeDeployment !== null || workflowData.isDeployed
59+
const isDeployed = deploymentSummary.activeDeployment !== null
5360

5461
if (!isDeployed) {
5562
logger.info(`[${requestId}] Workflow is not deployed: ${id}`)

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
ModalTabsList,
1818
ModalTabsTrigger,
1919
Tooltip,
20+
toast,
2021
} from '@sim/emcn'
2122
import { createLogger } from '@sim/logger'
2223
import { toError } from '@sim/utils/errors'
@@ -357,13 +358,22 @@ export function DeployModal({
357358
}
358359

359360
try {
360-
await undeployMutation.mutateAsync({ workflowId: targetWorkflowId })
361+
const result = await undeployMutation.mutateAsync({ workflowId: targetWorkflowId })
361362
if (!isWorkflowStillActive(targetWorkflowId)) return
362363
setUndeployTargetWorkflowId(null)
363364
onOpenChange(false)
365+
/**
366+
* Partial cleanup warnings (e.g. external subscription teardown left to
367+
* background retries) surface as a toast so closing the modal does not
368+
* silently swallow them.
369+
*/
370+
if (result.warnings?.length) {
371+
toast.warning('Workflow undeployed', { description: result.warnings.join(' ') })
372+
}
364373
} catch (error: unknown) {
365374
if (!isWorkflowStillActive(targetWorkflowId)) return
366375
logger.error('Error undeploying workflow:', { error })
376+
toast.error('Failed to undeploy workflow', { description: toError(error).message })
367377
}
368378
}
369379

apps/sim/background/async-preprocessing-correlation.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ describe('async preprocessing correlation threading', () => {
115115
status: 'active',
116116
archivedAt: null,
117117
lastQueuedAt: new Date('2025-01-01T00:00:00.000Z'),
118+
deploymentOperationId: null,
118119
},
119120
])
120121
mockLoadDeployedWorkflowState.mockResolvedValue({

apps/sim/background/webhook-execution.test.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ describe('executeWebhookJob fault vs error handling', () => {
293293
)
294294
})
295295

296-
it('does not start queued webhook work after the workflow is undeployed', async () => {
296+
it('acknowledges and skips queued webhook work after the workflow is undeployed', async () => {
297297
executionPreprocessingMockFns.mockPreprocessExecution.mockResolvedValueOnce({
298298
success: true,
299299
actorUserId: 'user-1',
@@ -308,10 +308,11 @@ describe('executeWebhookJob fault vs error handling', () => {
308308
executionTimeout: { async: 120_000 },
309309
})
310310

311-
await expect(executeWebhookJob(payload)).rejects.toThrow(
312-
'Workflow workflow-1 is no longer deployed'
313-
)
311+
const result = await executeWebhookJob(payload)
312+
313+
expect(result).toMatchObject({ skipped: true, success: false, workflowId: 'workflow-1' })
314314
expect(mockExecuteWorkflowCore).not.toHaveBeenCalled()
315+
expect(mockReleaseExecutionSlot).toHaveBeenCalled()
315316
})
316317

317318
it('releases the reservation when idempotency returns a cached result', async () => {

apps/sim/background/webhook-execution.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,25 @@ async function executeWebhookJobInternal(
413413
throw new Error(`Workflow ${payload.workflowId} not found during preprocessing`)
414414
}
415415
if (!workflowRecord.isDeployed || workflowRecord.archivedAt) {
416-
throw new Error(`Workflow ${payload.workflowId} is no longer deployed`)
416+
/**
417+
* A queued delivery racing an undeploy/archive is an expected terminal
418+
* condition, not a job fault: acknowledge and skip so workers do not
419+
* record a failed job (or burn retries) for work that must never run.
420+
*/
421+
logger.info(`[${requestId}] Skipping webhook execution for undeployed workflow`, {
422+
workflowId: payload.workflowId,
423+
archived: Boolean(workflowRecord.archivedAt),
424+
})
425+
await releaseExecutionSlot(executionId)
426+
return {
427+
success: false,
428+
skipped: true,
429+
workflowId: payload.workflowId,
430+
executionId,
431+
output: {},
432+
executedAt: new Date().toISOString(),
433+
provider: payload.provider,
434+
}
417435
}
418436

419437
const workspaceId = workflowRecord.workspaceId

0 commit comments

Comments
 (0)