Skip to content

Commit 33aa581

Browse files
committed
address comments
1 parent bc41ea0 commit 33aa581

File tree

2 files changed

+46
-3
lines changed

2 files changed

+46
-3
lines changed

apps/sim/executor/execution/engine.test.ts

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1067,7 +1067,7 @@ describe('ExecutionEngine', () => {
10671067
return {
10681068
nodeId,
10691069
output: { data: { fast: true }, status: 200, headers: {} },
1070-
isFinalOutput: false,
1070+
isFinalOutput: true,
10711071
}
10721072
}
10731073
if (nodeId === 'slow-work') {
@@ -1204,6 +1204,48 @@ describe('ExecutionEngine', () => {
12041204
expect(result.success).toBe(true)
12051205
expect(result.output).toEqual({ data: { response: true }, status: 200, headers: {} })
12061206
})
1207+
1208+
it('should honor locked Response output even when a parallel node throws an error', async () => {
1209+
const startNode = createMockNode('start', 'starter')
1210+
const responseNode = createMockNode('response', 'response')
1211+
const errorNode = createMockNode('error-node', 'function')
1212+
1213+
startNode.outgoingEdges.set('edge1', { target: 'response' })
1214+
startNode.outgoingEdges.set('edge2', { target: 'error-node' })
1215+
1216+
const dag = createMockDAG([startNode, responseNode, errorNode])
1217+
const context = createMockContext()
1218+
const edgeManager = createMockEdgeManager((node) => {
1219+
if (node.id === 'start') return ['response', 'error-node']
1220+
return []
1221+
})
1222+
1223+
const nodeOrchestrator = {
1224+
executionCount: 0,
1225+
executeNode: vi.fn().mockImplementation(async (_ctx: ExecutionContext, nodeId: string) => {
1226+
nodeOrchestrator.executionCount++
1227+
if (nodeId === 'response') {
1228+
return {
1229+
nodeId,
1230+
output: { data: { ok: true }, status: 200, headers: {} },
1231+
isFinalOutput: true,
1232+
}
1233+
}
1234+
if (nodeId === 'error-node') {
1235+
await new Promise((resolve) => setTimeout(resolve, 1))
1236+
throw new Error('Parallel branch failed')
1237+
}
1238+
return { nodeId, output: {}, isFinalOutput: false }
1239+
}),
1240+
handleNodeCompletion: vi.fn(),
1241+
} as unknown as MockNodeOrchestrator
1242+
1243+
const engine = new ExecutionEngine(context, dag, edgeManager, nodeOrchestrator)
1244+
const result = await engine.run('start')
1245+
1246+
expect(result.success).toBe(true)
1247+
expect(result.output).toEqual({ data: { ok: true }, status: 200, headers: {} })
1248+
})
12071249
})
12081250

12091251
describe('Cancellation flag behavior', () => {

apps/sim/executor/execution/engine.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,7 @@ export class ExecutionEngine {
128128
await this.waitForAllExecutions()
129129
}
130130

131-
// Rethrow the captured error so it's handled by the catch block
132-
if (this.errorFlag && this.executionError) {
131+
if (this.errorFlag && this.executionError && !this.responseOutputLocked) {
133132
throw this.executionError
134133
}
135134

@@ -401,6 +400,8 @@ export class ExecutionEngine {
401400
}
402401

403402
if (this.stoppedEarlyFlag && this.responseOutputLocked) {
403+
// Workflow already ended via Response block. Skip state persistence (setBlockOutput),
404+
// parallel/loop scope tracking, and edge propagation — no downstream blocks will run.
404405
return
405406
}
406407

0 commit comments

Comments
 (0)