@@ -23,6 +23,7 @@ import {
23
23
TaskRunExecution ,
24
24
timeout ,
25
25
TriggerConfig ,
26
+ UsageMeasurement ,
26
27
waitUntil ,
27
28
WorkerManifest ,
28
29
WorkerToExecutorMessageCatalog ,
@@ -232,7 +233,10 @@ async function bootstrap() {
232
233
233
234
let _execution : TaskRunExecution | undefined ;
234
235
let _isRunning = false ;
236
+ let _isCancelled = false ;
235
237
let _tracingSDK : TracingSDK | undefined ;
238
+ let _executionMeasurement : UsageMeasurement | undefined ;
239
+ const cancelController = new AbortController ( ) ;
236
240
237
241
const zodIpc = new ZodIpcConnection ( {
238
242
listenSchema : WorkerToExecutorMessageCatalog ,
@@ -403,18 +407,17 @@ const zodIpc = new ZodIpcConnection({
403
407
getNumberEnvVar ( "TRIGGER_RUN_METADATA_FLUSH_INTERVAL" , 1000 )
404
408
) ;
405
409
406
- const measurement = usage . start ( ) ;
410
+ _executionMeasurement = usage . start ( ) ;
407
411
408
- // This lives outside of the executor because this will eventually be moved to the controller level
409
- const signal = execution . run . maxDuration
410
- ? timeout . abortAfterTimeout ( execution . run . maxDuration )
411
- : undefined ;
412
+ const timeoutController = timeout . abortAfterTimeout ( execution . run . maxDuration ) ;
413
+
414
+ const signal = AbortSignal . any ( [ cancelController . signal , timeoutController . signal ] ) ;
412
415
413
416
const { result } = await executor . execute ( execution , metadata , traceContext , signal ) ;
414
417
415
- const usageSample = usage . stop ( measurement ) ;
418
+ if ( _isRunning && ! _isCancelled ) {
419
+ const usageSample = usage . stop ( _executionMeasurement ) ;
416
420
417
- if ( _isRunning ) {
418
421
return sender . send ( "TASK_RUN_COMPLETED" , {
419
422
execution,
420
423
result : {
@@ -458,7 +461,16 @@ const zodIpc = new ZodIpcConnection({
458
461
WAIT_COMPLETED_NOTIFICATION : async ( ) => {
459
462
await managedWorkerRuntime . completeWaitpoints ( [ ] ) ;
460
463
} ,
461
- FLUSH : async ( { timeoutInMs } , sender ) => {
464
+ CANCEL : async ( { timeoutInMs } ) => {
465
+ _isCancelled = true ;
466
+ cancelController . abort ( "run cancelled" ) ;
467
+ await callCancelHooks ( timeoutInMs ) ;
468
+ if ( _executionMeasurement ) {
469
+ usage . stop ( _executionMeasurement ) ;
470
+ }
471
+ await flushAll ( timeoutInMs ) ;
472
+ } ,
473
+ FLUSH : async ( { timeoutInMs } ) => {
462
474
await flushAll ( timeoutInMs ) ;
463
475
} ,
464
476
WAITPOINT_CREATED : async ( { wait, waitpoint } ) => {
@@ -470,6 +482,18 @@ const zodIpc = new ZodIpcConnection({
470
482
} ,
471
483
} ) ;
472
484
485
+ async function callCancelHooks ( timeoutInMs : number = 10_000 ) {
486
+ const now = performance . now ( ) ;
487
+
488
+ try {
489
+ await Promise . race ( [ lifecycleHooks . callOnCancelHookListeners ( ) , setTimeout ( timeoutInMs ) ] ) ;
490
+ } finally {
491
+ const duration = performance . now ( ) - now ;
492
+
493
+ log ( `Called cancel hooks in ${ duration } ms` ) ;
494
+ }
495
+ }
496
+
473
497
async function flushAll ( timeoutInMs : number = 10_000 ) {
474
498
const now = performance . now ( ) ;
475
499
0 commit comments