Skip to content

Commit 335ad5c

Browse files
waleedlatif1claude
andcommitted
fix(mothership): answer a workflow tool run that settles as its log is read with its result
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent b5d6485 commit 335ad5c

2 files changed

Lines changed: 20 additions & 1 deletion

File tree

‎apps/sim/lib/mothership/tools/handlers/workflow/mutations.test.ts‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,8 @@ describe('a workflow tool run past its wait', () => {
476476
executeRunWorkflow({ workflowId: 'workflow-1' }, { ...context, workflowRunWaitMs: 240_000 })
477477
)
478478
await vi.advanceTimersByTimeAsync(240_000)
479+
// The one-macrotask settle check after the log read (a 0 ms timer runs at 1 ms).
480+
await vi.advanceTimersByTimeAsync(1)
479481
const result = await answer
480482
const executionId = run.lifecycle().executionId
481483
expect(executionId).toEqual(expect.any(String))
@@ -525,11 +527,26 @@ describe('a workflow tool run past its wait', () => {
525527
await vi.advanceTimersByTimeAsync(1_000)
526528
expect(answered).toBe(false)
527529
await vi.advanceTimersByTimeAsync(1_000)
530+
await vi.advanceTimersByTimeAsync(1)
528531
await expect(answer).resolves.toMatchObject({ output: { status: 'running' } })
529532
expect(mocks.logStatus).toHaveBeenCalledWith(run.lifecycle().executionId, 'workflow-1')
530533
run.settle({ success: true, output: {}, logs: [] })
531534
})
532535

536+
it('answers a run that settles as its log read returns with how it settled', async () => {
537+
const run = pendingRun()
538+
mocks.logStatus.mockReset().mockImplementation(async () => {
539+
queueMicrotask(() => run.settle({ success: true, output: { value: 5 }, logs: [] }))
540+
return 'running'
541+
})
542+
const answer = executeRunWorkflow(
543+
{ workflowId: 'workflow-1' },
544+
{ ...context, workflowRunWaitMs: 1_000 }
545+
)
546+
await vi.advanceTimersByTimeAsync(1_000)
547+
await expect(answer).resolves.toMatchObject({ success: true, output: { output: { value: 5 } } })
548+
})
549+
533550
it('keeps waiting on a run past its wait when its log cannot be read', async () => {
534551
const run = pendingRun()
535552
mocks.logStatus.mockReset().mockRejectedValue(new Error('db down'))
@@ -574,6 +591,7 @@ describe('a workflow tool run past its wait', () => {
574591
{ ...context, boundWorkflowExecutionId: 'bound-1', workflowRunWaitMs: 1_000 }
575592
)
576593
await vi.advanceTimersByTimeAsync(1_000)
594+
await vi.advanceTimersByTimeAsync(1)
577595
await expect(answer).resolves.toMatchObject({
578596
output: { status: 'running', executionId: 'bound-1' },
579597
})

‎apps/sim/lib/mothership/tools/handlers/workflow/mutations.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -325,10 +325,11 @@ async function answerWithinWait(
325325
readable = await runIsReadable(executionId, workflowId)
326326
if (!readable) await Promise.race([finished, waited(RUN_LOG_POLL_MS)])
327327
}
328+
// One macrotask lets a run that settled as its log was read deliver its result first.
329+
if (!outcome.current) await Promise.race([finished, waited(0)])
328330
} finally {
329331
stopWaiting.abort()
330332
}
331-
// A run that settled while its log was being read answers with how it settled.
332333
if (outcome.current?.ok === false) throw outcome.current.error
333334
if (outcome.current) return outcome.current.result
334335
logger.info('Workflow tool run outlasted its wait; answering it still running', {

0 commit comments

Comments
 (0)