@@ -125,6 +125,21 @@ export async function executeJobCoreWithTimeout(
125125 opts ?: { runId ?: string } ,
126126) : Promise < Awaited < ReturnType < typeof executeJobCore > > > {
127127 const runAbortController = new AbortController ( ) ;
128+ const operatorCancellationMarker = Symbol ( "cron-operator-cancelled" ) ;
129+ let resolveOperatorCancellation : ( ( value : typeof operatorCancellationMarker ) => void ) | undefined ;
130+ const operatorCancellationPromise = new Promise < typeof operatorCancellationMarker > ( ( resolve ) => {
131+ resolveOperatorCancellation = resolve ;
132+ } ) ;
133+ const createOperatorCancellationOutcome = ( ) => {
134+ const error = abortErrorMessage ( runAbortController . signal ) ;
135+ return {
136+ status : "error" as const ,
137+ error,
138+ diagnostics : createCronRunDiagnosticsFromError ( "cron-setup" , error , {
139+ nowMs : state . deps . nowMs ,
140+ } ) ,
141+ } ;
142+ } ;
128143 // Main-session cron jobs enqueue work into a downstream child session. The
129144 // cron wrapper does not own that queued run, so it must not expose a task
130145 // cancellation handle that could make the wrapper row lie about child state.
@@ -133,20 +148,12 @@ export async function executeJobCoreWithTimeout(
133148 ? registerActiveCronTaskRun ( {
134149 runId : opts ?. runId ,
135150 controller : runAbortController ,
151+ onCancel : ( ) => resolveOperatorCancellation ?.( operatorCancellationMarker ) ,
136152 } )
137153 : undefined ;
138154 const jobTimeoutMs = resolveCronJobTimeoutMs ( job ) ;
139155 try {
140156 if ( typeof jobTimeoutMs !== "number" ) {
141- const cancellationMarker = Symbol ( "cron-cancelled" ) ;
142- const cancellationPromise = new Promise < typeof cancellationMarker > ( ( resolve ) => {
143- const resolveCancelled = ( ) => resolve ( cancellationMarker ) ;
144- if ( runAbortController . signal . aborted ) {
145- resolveCancelled ( ) ;
146- return ;
147- }
148- runAbortController . signal . addEventListener ( "abort" , resolveCancelled , { once : true } ) ;
149- } ) ;
150157 const corePromise = executeJobCore ( state , job , runAbortController . signal ) ;
151158 void corePromise . catch ( ( err : unknown ) => {
152159 if ( runAbortController . signal . aborted ) {
@@ -156,18 +163,11 @@ export async function executeJobCoreWithTimeout(
156163 ) ;
157164 }
158165 } ) ;
159- const first = await Promise . race ( [ corePromise , cancellationPromise ] ) ;
160- if ( first !== cancellationMarker ) {
166+ const first = await Promise . race ( [ corePromise , operatorCancellationPromise ] ) ;
167+ if ( first !== operatorCancellationMarker ) {
161168 return first ;
162169 }
163- const error = abortErrorMessage ( runAbortController . signal ) ;
164- return {
165- status : "error" ,
166- error,
167- diagnostics : createCronRunDiagnosticsFromError ( "cron-setup" , error , {
168- nowMs : state . deps . nowMs ,
169- } ) ,
170- } ;
170+ return createOperatorCancellationOutcome ( ) ;
171171 }
172172
173173 let timeoutReason : string | undefined ;
@@ -207,7 +207,10 @@ export async function executeJobCoreWithTimeout(
207207 }
208208 } ) ;
209209 try {
210- const first = await Promise . race ( [ corePromise , timeoutPromise ] ) ;
210+ const first = await Promise . race ( [ corePromise , timeoutPromise , operatorCancellationPromise ] ) ;
211+ if ( first === operatorCancellationMarker ) {
212+ return createOperatorCancellationOutcome ( ) ;
213+ }
211214 if ( first !== timeoutMarker ) {
212215 return first ;
213216 }
0 commit comments