@@ -292,6 +292,67 @@ async function completePausedCancellationWithRetry(
292292 return false
293293}
294294
295+ async function clearPausedCancellationIntentWithRetry (
296+ executionId : string ,
297+ workflowId : string
298+ ) : Promise < boolean > {
299+ for ( let attempt = 1 ; attempt <= PAUSED_CANCELLATION_DB_ATTEMPTS ; attempt ++ ) {
300+ try {
301+ await PauseResumeManager . clearPausedCancellationIntent ( executionId , workflowId )
302+ return true
303+ } catch ( error ) {
304+ logger . warn ( 'Failed to clear paused cancellation intent' , {
305+ executionId,
306+ attempt,
307+ error : toError ( error ) . message ,
308+ } )
309+ if ( attempt < PAUSED_CANCELLATION_DB_ATTEMPTS ) {
310+ await sleep ( PAUSED_CANCELLATION_DB_RETRY_MS )
311+ }
312+ }
313+ }
314+ return false
315+ }
316+
317+ async function restorePausedCancellationAfterRejectedCommit ( args : {
318+ executionId : string
319+ workflowId : string
320+ effectivePausedCancellationPath : boolean
321+ activeResumeEntryId : string | null
322+ } ) : Promise < boolean > {
323+ if ( ! args . effectivePausedCancellationPath ) return true
324+
325+ if ( args . activeResumeEntryId ) {
326+ try {
327+ const rolledBack = await PauseResumeManager . rollbackActiveResumeCancellation (
328+ args . executionId ,
329+ args . workflowId ,
330+ args . activeResumeEntryId
331+ )
332+ if ( rolledBack ) return true
333+ logger . warn ( 'Active resume rollback was rejected; clearing paused cancellation intent' , {
334+ executionId : args . executionId ,
335+ activeResumeEntryId : args . activeResumeEntryId ,
336+ } )
337+ } catch ( error ) {
338+ logger . warn ( 'Active resume rollback failed; clearing paused cancellation intent' , {
339+ executionId : args . executionId ,
340+ activeResumeEntryId : args . activeResumeEntryId ,
341+ error : toError ( error ) . message ,
342+ } )
343+ }
344+ }
345+
346+ return clearPausedCancellationIntentWithRetry ( args . executionId , args . workflowId )
347+ }
348+
349+ function throwPausedCancellationRestoreFailed ( ) : never {
350+ throw new OrchestrationError (
351+ 'internal' ,
352+ 'Failed to restore paused execution after cancellation was rejected'
353+ )
354+ }
355+
295356async function ensureCancellationEventPublished (
296357 executionId : string ,
297358 workflowId : string ,
@@ -681,6 +742,12 @@ export async function cancelWorkflowExecution({
681742 }
682743
683744 if ( execution . status !== 'running' && execution . status !== 'pending' ) {
745+ const pausedCancellationRestored = await clearPausedCancellationIntentWithRetry (
746+ executionId ,
747+ workflowId
748+ )
749+ if ( ! pausedCancellationRestored ) throwPausedCancellationRestoreFailed ( )
750+
684751 if ( ! isWorkflowGroupExecution && isWorkflowRunAlreadyTerminalStatus ( execution . status ) ) {
685752 throw new WorkflowRunAlreadyTerminalError ( {
686753 executionId,
@@ -853,28 +920,13 @@ export async function cancelWorkflowExecution({
853920
854921 if ( workflowGroupNoLongerActive ) {
855922 await clearStopSignalMarkers ( stopSummary )
856- if ( activeResumeEntryId ) {
857- await PauseResumeManager . rollbackActiveResumeCancellation (
858- executionId ,
859- workflowId ,
860- activeResumeEntryId
861- ) . catch ( ( error ) => {
862- logger . warn ( 'Failed to roll back active resume after group target disappeared' , {
863- executionId,
864- activeResumeEntryId,
865- error : toError ( error ) . message ,
866- } )
867- } )
868- } else if ( effectivePausedCancellationPath ) {
869- await PauseResumeManager . clearPausedCancellationIntent ( executionId , workflowId ) . catch (
870- ( error ) => {
871- logger . warn ( 'Failed to clear cancellation intent after group target disappeared' , {
872- executionId,
873- error : toError ( error ) . message ,
874- } )
875- }
876- )
877- }
923+ const pausedCancellationRestored = await restorePausedCancellationAfterRejectedCommit ( {
924+ executionId,
925+ workflowId,
926+ effectivePausedCancellationPath,
927+ activeResumeEntryId,
928+ } )
929+ if ( ! pausedCancellationRestored ) throwPausedCancellationRestoreFailed ( )
878930 throw new OrchestrationError (
879931 'conflict' ,
880932 'Workflow group execution is no longer the active table execution'
@@ -883,28 +935,13 @@ export async function cancelWorkflowExecution({
883935
884936 if ( competingTerminalStatus ) {
885937 await clearStopSignalMarkers ( stopSummary )
886- if ( activeResumeEntryId ) {
887- await PauseResumeManager . rollbackActiveResumeCancellation (
888- executionId ,
889- workflowId ,
890- activeResumeEntryId
891- ) . catch ( ( error ) => {
892- logger . warn ( 'Failed to roll back active resume after terminal race' , {
893- executionId,
894- activeResumeEntryId,
895- error : toError ( error ) . message ,
896- } )
897- } )
898- } else if ( effectivePausedCancellationPath ) {
899- await PauseResumeManager . clearPausedCancellationIntent ( executionId , workflowId ) . catch (
900- ( error ) => {
901- logger . warn ( 'Failed to clear cancellation intent after terminal race' , {
902- executionId,
903- error : toError ( error ) . message ,
904- } )
905- }
906- )
907- }
938+ const pausedCancellationRestored = await restorePausedCancellationAfterRejectedCommit ( {
939+ executionId,
940+ workflowId,
941+ effectivePausedCancellationPath,
942+ activeResumeEntryId,
943+ } )
944+ if ( ! pausedCancellationRestored ) throwPausedCancellationRestoreFailed ( )
908945 if (
909946 ! isWorkflowGroupExecution &&
910947 isWorkflowRunAlreadyTerminalStatus ( competingTerminalStatus )
0 commit comments