File tree Expand file tree Collapse file tree
apps/sim/lib/execution/remote-sandbox Expand file tree Collapse file tree Original file line number Diff line number Diff 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' )
Original file line number Diff line number Diff 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' ,
You can’t perform that action at this time.
0 commit comments