@@ -1094,6 +1094,64 @@ describe('POST /api/workflows/[id]/executions/[executionId]/cancel', () => {
10941094 expect ( mockMarkExecutionCancelled ) . not . toHaveBeenCalled ( )
10951095 } )
10961096
1097+ it ( 'rolls back pause staging for an already-cancelled execution when cancellation is aborted' , async ( ) => {
1098+ const controller = new AbortController ( )
1099+ dbChainMockFns . limit . mockResolvedValueOnce ( [
1100+ {
1101+ executionDeadlineAt : null ,
1102+ executionOrigin : null ,
1103+ status : 'cancelled' ,
1104+ workspaceId : 'workspace-1' ,
1105+ } ,
1106+ ] )
1107+ mockStagePausedCancellation . mockImplementationOnce ( async ( ) => {
1108+ controller . abort ( )
1109+ return { kind : 'idle' }
1110+ } )
1111+
1112+ const response = await cancelWorkflowExecutionPostAuth ( {
1113+ workflowId : 'wf-1' ,
1114+ executionId : 'ex-1' ,
1115+ userId : 'user-1' ,
1116+ abortSignal : controller . signal ,
1117+ } )
1118+
1119+ expect ( response . status ) . toBe ( 409 )
1120+ expect ( mockClearPausedCancellationIntent ) . toHaveBeenCalledWith ( 'ex-1' , 'wf-1' )
1121+ expect ( mockWriteTerminalEvent ) . not . toHaveBeenCalled ( )
1122+ expect ( mockCompletePausedCancellation ) . not . toHaveBeenCalled ( )
1123+ expect ( mockReleaseExecutionSlot ) . not . toHaveBeenCalled ( )
1124+ } )
1125+
1126+ it ( 'finishes cancellation when an aborted active-resume stage cannot be rolled back' , async ( ) => {
1127+ const controller = new AbortController ( )
1128+ mockStagePausedCancellation . mockImplementationOnce ( async ( ) => {
1129+ controller . abort ( )
1130+ return { kind : 'active_resume' , target : ACTIVE_RESUME_TARGET }
1131+ } )
1132+ mockRollbackActiveResumeCancellation . mockResolvedValueOnce ( false )
1133+ mockMarkExecutionCancelled . mockResolvedValue ( { durablyRecorded : true , reason : 'recorded' } )
1134+ mockCompletePausedCancellation . mockResolvedValue ( true )
1135+
1136+ const response = await cancelWorkflowExecutionPostAuth ( {
1137+ workflowId : 'wf-1' ,
1138+ executionId : 'ex-1' ,
1139+ userId : 'user-1' ,
1140+ abortSignal : controller . signal ,
1141+ } )
1142+
1143+ expect ( response . status ) . toBe ( 200 )
1144+ await expect ( response . json ( ) ) . resolves . toMatchObject ( { success : true , pausedCancelled : true } )
1145+ expect ( mockRollbackActiveResumeCancellation ) . toHaveBeenCalledWith (
1146+ 'ex-1' ,
1147+ 'wf-1' ,
1148+ 'resume-entry-1'
1149+ )
1150+ expect ( mockMarkExecutionCancelled ) . toHaveBeenCalledWith ( 'resume-ex-1' , {
1151+ executionDeadlineAt : null ,
1152+ } )
1153+ } )
1154+
10971155 it ( 'returns 404 when the execution does not belong to the workflow' , async ( ) => {
10981156 dbChainMockFns . limit . mockResolvedValueOnce ( [ ] )
10991157
0 commit comments