Skip to content

Commit a8e6e0a

Browse files
fix(async): clean stale finalization guards
Scan all finalized execution ids during TTL cleanup so refreshed keys cannot keep expired guards alive, and cover the reused-id ordering regression.
1 parent 42cc70c commit a8e6e0a

File tree

2 files changed

+60
-4
lines changed

2 files changed

+60
-4
lines changed

apps/sim/lib/workflows/executor/execution-core.test.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,64 @@ describe('executeWorkflowCore terminal finalization sequencing', () => {
382382
expect(wasExecutionFinalizedByCore('engine failed', 'execution-fresh')).toBe(true)
383383
})
384384

385+
it('removes expired finalized ids even when a reused id stays earlier in map order', async () => {
386+
vi.useFakeTimers()
387+
vi.setSystemTime(new Date('2026-03-13T00:00:00.000Z'))
388+
389+
executorExecuteMock.mockRejectedValue('engine failed')
390+
391+
await expect(
392+
executeWorkflowCore({
393+
snapshot: {
394+
...createSnapshot(),
395+
metadata: {
396+
...createSnapshot().metadata,
397+
executionId: 'execution-a',
398+
},
399+
} as any,
400+
callbacks: {},
401+
loggingSession: loggingSession as any,
402+
})
403+
).rejects.toBe('engine failed')
404+
405+
vi.setSystemTime(new Date('2026-03-13T00:01:00.000Z'))
406+
407+
await expect(
408+
executeWorkflowCore({
409+
snapshot: {
410+
...createSnapshot(),
411+
metadata: {
412+
...createSnapshot().metadata,
413+
executionId: 'execution-b',
414+
},
415+
} as any,
416+
callbacks: {},
417+
loggingSession: loggingSession as any,
418+
})
419+
).rejects.toBe('engine failed')
420+
421+
vi.setSystemTime(new Date('2026-03-13T00:02:00.000Z'))
422+
423+
await expect(
424+
executeWorkflowCore({
425+
snapshot: {
426+
...createSnapshot(),
427+
metadata: {
428+
...createSnapshot().metadata,
429+
executionId: 'execution-a',
430+
},
431+
} as any,
432+
callbacks: {},
433+
loggingSession: loggingSession as any,
434+
})
435+
).rejects.toBe('engine failed')
436+
437+
vi.setSystemTime(new Date('2026-03-13T00:06:01.000Z'))
438+
439+
expect(wasExecutionFinalizedByCore('engine failed', 'execution-b')).toBe(false)
440+
expect(wasExecutionFinalizedByCore('engine failed', 'execution-a')).toBe(true)
441+
})
442+
385443
it('falls back to error finalization when success finalization rejects', async () => {
386444
executorExecuteMock.mockResolvedValue({
387445
success: true,

apps/sim/lib/workflows/executor/execution-core.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,9 @@ const finalizedExecutionIds = new Map<string, number>()
122122

123123
function cleanupExpiredFinalizedExecutionIds(now = Date.now()): void {
124124
for (const [executionId, expiresAt] of finalizedExecutionIds.entries()) {
125-
if (expiresAt > now) {
126-
break
125+
if (expiresAt <= now) {
126+
finalizedExecutionIds.delete(executionId)
127127
}
128-
129-
finalizedExecutionIds.delete(executionId)
130128
}
131129
}
132130

0 commit comments

Comments
 (0)