@@ -87,6 +87,10 @@ interface ExecutionStopSummary extends ExecutionStopSignalResult {
8787 signalledExecutionIds : Set < string >
8888}
8989
90+ type ActiveResumeCancellationTarget = NonNullable <
91+ Awaited < ReturnType < typeof PauseResumeManager . getActiveResumeCancellationTarget > >
92+ >
93+
9094function createExecutionStopSummary ( ) : ExecutionStopSummary {
9195 return {
9296 cancellation : { durablyRecorded : false , reason : 'redis_unavailable' } ,
@@ -142,35 +146,28 @@ async function signalExecutionStop(args: {
142146 }
143147}
144148
145- async function signalActiveResumeStop ( args : {
149+ async function signalAndRecordActiveResumeStop ( args : {
146150 workflowId : string
147151 executionId : string
148152 executionDeadlineAt : Date | null
149- target : NonNullable <
150- Awaited < ReturnType < typeof PauseResumeManager . getActiveResumeCancellationTarget > >
151- >
152- } ) : Promise < {
153- target : NonNullable <
154- Awaited < ReturnType < typeof PauseResumeManager . getActiveResumeCancellationTarget > >
155- >
156- signal : ExecutionStopSignalResult
157- } > {
153+ target : ActiveResumeCancellationTarget
154+ summary : ExecutionStopSummary
155+ } ) : Promise < boolean > {
158156 const signal = await signalExecutionStop ( {
159157 workflowId : args . workflowId ,
160158 signalExecutionId : args . target . resumeExecutionId ,
161159 queueBindingExecutionId : args . executionId ,
162160 executionDeadlineAt : args . executionDeadlineAt ,
163161 queueScope : 'resume' ,
164162 } )
165- return { target : args . target , signal }
163+ mergeExecutionStopSignal ( args . summary , args . target . resumeExecutionId , signal )
164+ return didActiveResumeStop ( args . executionId , args . workflowId , args . target , signal )
166165}
167166
168167async function didActiveResumeStop (
169168 executionId : string ,
170169 workflowId : string ,
171- target : NonNullable <
172- Awaited < ReturnType < typeof PauseResumeManager . getActiveResumeCancellationTarget > >
173- > ,
170+ target : ActiveResumeCancellationTarget ,
174171 signal : ExecutionStopSignalResult
175172) : Promise < boolean > {
176173 if ( signal . accepted ) return true
@@ -375,7 +372,33 @@ async function rollbackPausedCancellationAfterAbort(args: {
375372 return abortResponse
376373}
377374
378- /** Runs the existing workflow cancellation lifecycle after surface authentication. */
375+ function resolveCancellationReason ( args : {
376+ activeResumeSignalFailed : boolean
377+ pauseReconciliationFailed : boolean
378+ effectivePausedCancellationPath : boolean
379+ cancellationEventPublished : boolean
380+ pausedCancelled : boolean
381+ stopSummary : ExecutionStopSummary
382+ } ) : NonNullable < CancelWorkflowExecutionResponse [ 'reason' ] > {
383+ if ( args . activeResumeSignalFailed ) return 'active_resume_signal_failed'
384+ if ( args . pauseReconciliationFailed ) return 'paused_database_cancel_failed'
385+ if ( args . effectivePausedCancellationPath && ! args . cancellationEventPublished ) {
386+ return 'paused_event_publish_failed'
387+ }
388+ if ( args . effectivePausedCancellationPath && ! args . pausedCancelled ) {
389+ return 'paused_database_cancel_failed'
390+ }
391+ if ( args . effectivePausedCancellationPath ) return 'recorded'
392+ if (
393+ args . stopSummary . queueJobsCancelled > 0 &&
394+ ! args . stopSummary . cancellation . durablyRecorded &&
395+ ! args . stopSummary . locallyAborted
396+ ) {
397+ return 'queue_cancelled'
398+ }
399+ return args . stopSummary . cancellation . reason
400+ }
401+
379402export async function cancelWorkflowExecutionPostAuth ( {
380403 workflowId,
381404 executionId,
@@ -544,23 +567,13 @@ export async function cancelWorkflowExecutionPostAuth({
544567 let activeResumeSignalFailed = false
545568 let exactStopSatisfied = true
546569 if ( pausedCancellationStage . kind === 'active_resume' ) {
547- const activeResumeStop = await signalActiveResumeStop ( {
570+ exactStopSatisfied = await signalAndRecordActiveResumeStop ( {
548571 workflowId,
549572 executionId,
550573 executionDeadlineAt : execution . executionDeadlineAt ,
551574 target : pausedCancellationStage . target ,
575+ summary : stopSummary ,
552576 } )
553- mergeExecutionStopSignal (
554- stopSummary ,
555- activeResumeStop . target . resumeExecutionId ,
556- activeResumeStop . signal
557- )
558- exactStopSatisfied = await didActiveResumeStop (
559- executionId ,
560- workflowId ,
561- activeResumeStop . target ,
562- activeResumeStop . signal
563- )
564577 activeResumeSignalFailed = ! exactStopSatisfied
565578 } else if ( isWorkflowGroupExecution && ! hasPausedCancellation ) {
566579 const retrySignal = await signalExecutionStop ( {
@@ -657,23 +670,13 @@ export async function cancelWorkflowExecutionPostAuth({
657670 let activeResumeSignalAccepted = false
658671
659672 if ( activeResumeTarget && ! isWorkflowGroupExecution ) {
660- const activeResumeStop = await signalActiveResumeStop ( {
673+ activeResumeSignalAccepted = await signalAndRecordActiveResumeStop ( {
661674 workflowId,
662675 executionId,
663676 executionDeadlineAt : execution . executionDeadlineAt ,
664677 target : activeResumeTarget ,
678+ summary : stopSummary ,
665679 } )
666- mergeExecutionStopSignal (
667- stopSummary ,
668- activeResumeStop . target . resumeExecutionId ,
669- activeResumeStop . signal
670- )
671- activeResumeSignalAccepted = await didActiveResumeStop (
672- executionId ,
673- workflowId ,
674- activeResumeStop . target ,
675- activeResumeStop . signal
676- )
677680
678681 if ( ! activeResumeSignalAccepted ) {
679682 const failedResumeEntryId = activeResumeTarget . resumeEntryId
@@ -730,23 +733,13 @@ export async function cancelWorkflowExecutionPostAuth({
730733 activeResumeEntryId = activeResumeTarget ?. resumeEntryId ?? null
731734
732735 if ( activeResumeTarget ) {
733- const activeResumeStop = await signalActiveResumeStop ( {
736+ activeResumeSignalAccepted = await signalAndRecordActiveResumeStop ( {
734737 workflowId,
735738 executionId,
736739 executionDeadlineAt : execution . executionDeadlineAt ,
737740 target : activeResumeTarget ,
741+ summary : stopSummary ,
738742 } )
739- mergeExecutionStopSignal (
740- stopSummary ,
741- activeResumeStop . target . resumeExecutionId ,
742- activeResumeStop . signal
743- )
744- activeResumeSignalAccepted = await didActiveResumeStop (
745- executionId ,
746- workflowId ,
747- activeResumeStop . target ,
748- activeResumeStop . signal
749- )
750743 if ( ! activeResumeSignalAccepted ) {
751744 const failedResumeEntryId = activeResumeTarget . resumeEntryId
752745 await PauseResumeManager . rollbackActiveResumeCancellation (
@@ -919,23 +912,13 @@ export async function cancelWorkflowExecutionPostAuth({
919912 let activeResumeSignalFailed = false
920913 if ( isWorkflowGroupExecution ) {
921914 if ( activeResumeTarget ) {
922- const activeResumeStop = await signalActiveResumeStop ( {
915+ activeResumeSignalAccepted = await signalAndRecordActiveResumeStop ( {
923916 workflowId,
924917 executionId,
925918 executionDeadlineAt : execution . executionDeadlineAt ,
926919 target : activeResumeTarget ,
920+ summary : stopSummary ,
927921 } )
928- mergeExecutionStopSignal (
929- stopSummary ,
930- activeResumeStop . target . resumeExecutionId ,
931- activeResumeStop . signal
932- )
933- activeResumeSignalAccepted = await didActiveResumeStop (
934- executionId ,
935- workflowId ,
936- activeResumeStop . target ,
937- activeResumeStop . signal
938- )
939922 activeResumeSignalFailed = ! activeResumeSignalAccepted
940923 } else if ( ! effectivePausedCancellationPath ) {
941924 const groupSignal = await signalExecutionStop ( {
@@ -954,32 +937,19 @@ export async function cancelWorkflowExecutionPostAuth({
954937 )
955938 if ( isPausedCancellationStage ( postClaimPausedCancellationStage ) ) {
956939 effectivePausedCancellationPath = true
957- pausedCancellationStage = postClaimPausedCancellationStage
958940 if ( postClaimPausedCancellationStage . kind === 'active_resume' ) {
959941 const currentActiveResume = postClaimPausedCancellationStage . target
960942 const alreadyAttemptedCurrentResume =
961943 currentActiveResume . resumeEntryId === activeResumeEntryId &&
962944 stopSummary . signalledExecutionIds . has ( currentActiveResume . resumeExecutionId )
963945 if ( ! alreadyAttemptedCurrentResume ) {
964- const activeResumeStop = await signalActiveResumeStop ( {
946+ activeResumeSignalAccepted = await signalAndRecordActiveResumeStop ( {
965947 workflowId,
966948 executionId,
967949 executionDeadlineAt : execution . executionDeadlineAt ,
968950 target : currentActiveResume ,
951+ summary : stopSummary ,
969952 } )
970- activeResumeEntryId = activeResumeStop . target . resumeEntryId
971- activeResumeTarget = activeResumeStop . target
972- mergeExecutionStopSignal (
973- stopSummary ,
974- activeResumeStop . target . resumeExecutionId ,
975- activeResumeStop . signal
976- )
977- activeResumeSignalAccepted = await didActiveResumeStop (
978- executionId ,
979- workflowId ,
980- activeResumeStop . target ,
981- activeResumeStop . signal
982- )
983953 }
984954 activeResumeSignalFailed = ! activeResumeSignalAccepted
985955 } else {
@@ -1046,21 +1016,14 @@ export async function cancelWorkflowExecutionPostAuth({
10461016 const durablyRecorded = effectivePausedCancellationPath
10471017 ? true
10481018 : stopSummary . cancellation . durablyRecorded
1049- const reason = activeResumeSignalFailed
1050- ? 'active_resume_signal_failed'
1051- : pauseReconciliationFailed
1052- ? 'paused_database_cancel_failed'
1053- : effectivePausedCancellationPath && ! cancellationEventPublished
1054- ? 'paused_event_publish_failed'
1055- : effectivePausedCancellationPath && ! pausedCancelled
1056- ? 'paused_database_cancel_failed'
1057- : effectivePausedCancellationPath
1058- ? 'recorded'
1059- : stopSummary . queueJobsCancelled > 0 &&
1060- ! stopSummary . cancellation . durablyRecorded &&
1061- ! stopSummary . locallyAborted
1062- ? 'queue_cancelled'
1063- : stopSummary . cancellation . reason
1019+ const reason = resolveCancellationReason ( {
1020+ activeResumeSignalFailed,
1021+ pauseReconciliationFailed,
1022+ effectivePausedCancellationPath,
1023+ cancellationEventPublished,
1024+ pausedCancelled,
1025+ stopSummary,
1026+ } )
10641027
10651028 return cancellationOutcome ( {
10661029 success,
@@ -1075,13 +1038,14 @@ export async function cancelWorkflowExecutionPostAuth({
10751038 reason,
10761039 } )
10771040 } catch ( error ) {
1041+ const normalizedError = toError ( error )
10781042 logger . error ( 'Failed to cancel execution' , {
10791043 workflowId,
10801044 executionId,
1081- error : toError ( error ) . message ,
1045+ error : normalizedError . message ,
10821046 } )
10831047 return NextResponse . json (
1084- { error : toError ( error ) . message || 'Failed to cancel execution' } ,
1048+ { error : normalizedError . message || 'Failed to cancel execution' } ,
10851049 { status : 500 }
10861050 )
10871051 }
0 commit comments