Skip to content

Commit 75dcdbf

Browse files
committed
fix(sandbox): keep a cancellation during the timed-out output listing a cancellation
1 parent 4030b6f commit 75dcdbf

2 files changed

Lines changed: 35 additions & 1 deletion

File tree

‎apps/sim/lib/execution/remote-sandbox/index.ts‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ async function throwIfRunTimedOut(
279279
lease: SandboxLease
280280
outputSandboxDir: string | undefined
281281
timeoutMs: number
282+
signal: AbortSignal
282283
}
283284
): Promise<void> {
284285
if (!result.timedOut) return
@@ -287,9 +288,12 @@ async function throwIfRunTimedOut(
287288
const listed = outputSandboxDir
288289
? await withinDeadline(
289290
() => sandbox.listFiles(outputSandboxDir, { depth: SANDBOX_OUTPUT_DIR_MAX_DEPTH }),
290-
Date.now() + TIMED_OUT_OUTPUT_LISTING_MS
291+
Date.now() + TIMED_OUT_OUTPUT_LISTING_MS,
292+
run.signal
291293
).catch(() => [])
292294
: []
295+
// A cancellation that arrives while listing stays a cancellation.
296+
throwIfAborted(run.signal)
293297
throw new SandboxExecutionTimeoutError(sandboxTimeoutProgress(streams, run.timeoutMs, listed))
294298
}
295299

@@ -1025,6 +1029,7 @@ async function executeInSandboxWithinBudget(
10251029
lease,
10261030
outputSandboxDir: req.outputSandboxDir,
10271031
timeoutMs: runTimeoutMs,
1032+
signal,
10281033
})
10291034

10301035
if (execution.error) {
@@ -1236,6 +1241,7 @@ async function executeShellInSandboxWithinBudget(
12361241
lease,
12371242
outputSandboxDir: req.outputSandboxDir,
12381243
timeoutMs: runTimeoutMs,
1244+
signal,
12391245
})
12401246

12411247
const stdout = [result.stdout, result.stderr].filter(Boolean).join('\n')

‎apps/sim/lib/execution/remote-sandbox/session-sandbox.test.ts‎

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,6 +1038,34 @@ describe('session sandbox lease', () => {
10381038
}
10391039
})
10401040

1041+
it('keeps a cancellation that arrives while listing the outputs a cancellation', async () => {
1042+
const { handle } = fakeSandbox('timeout-cancelled')
1043+
mockFindSessionSandbox.mockResolvedValue(handle)
1044+
const controller = new AbortController()
1045+
handle.runCommand = async () => ({
1046+
stdout: 'step 1',
1047+
stderr: '',
1048+
exitCode: 124,
1049+
timedOut: true,
1050+
})
1051+
handle.listFiles = async () => {
1052+
controller.abort(new Error('User Stop'))
1053+
return new Promise<never>(() => {})
1054+
}
1055+
const error = await executeShellInSandbox({
1056+
...CODE_REQUEST,
1057+
envs: {},
1058+
session: { key: 'timeout-cancelled' },
1059+
outputSandboxDir: OUTPUT_DIR,
1060+
signal: controller.signal,
1061+
}).then(
1062+
() => undefined,
1063+
(rejection: unknown) => rejection
1064+
)
1065+
expect(error).not.toBeInstanceOf(SandboxExecutionTimeoutError)
1066+
expect(isTimeoutAbortReason(error)).toBe(false)
1067+
})
1068+
10411069
it('withholds the output when the workbench secret provenance is unavailable', async () => {
10421070
const error = await timedOutRun(
10431071
'shell',

0 commit comments

Comments
 (0)