4
4
RunFnParams ,
5
5
ServerBackgroundWorker ,
6
6
TaskMetadataWithFunctions ,
7
+ TaskRunErrorCodes ,
7
8
TaskRunExecution ,
8
9
} from "../src/v3/index.js" ;
9
10
import { TracingSDK } from "../src/v3/otel/tracingSDK.js" ;
@@ -52,7 +53,7 @@ describe("TaskExecutor", () => {
52
53
} ,
53
54
} ;
54
55
55
- const result = await executeTask ( task , { } ) ;
56
+ const result = await executeTask ( task , { } , undefined ) ;
56
57
57
58
expect ( result ) . toEqual ( {
58
59
result : {
@@ -136,7 +137,7 @@ describe("TaskExecutor", () => {
136
137
} ,
137
138
} ;
138
139
139
- const result = await executeTask ( task , { } ) ;
140
+ const result = await executeTask ( task , { } , undefined ) ;
140
141
141
142
// Verify hooks were called in correct order - should match registration order
142
143
expect ( globalSuccessOrder ) . toEqual ( [ "global-2" , "global-1" , "task" ] ) ;
@@ -238,7 +239,7 @@ describe("TaskExecutor", () => {
238
239
} ,
239
240
} ;
240
241
241
- const result = await executeTask ( task , { test : "data" } ) ;
242
+ const result = await executeTask ( task , { test : "data" } , undefined ) ;
242
243
243
244
// Verify hooks were called in correct order
244
245
expect ( globalStartOrder ) . toEqual ( [ "global-1" , "global-2" , "task" ] ) ;
@@ -337,7 +338,7 @@ describe("TaskExecutor", () => {
337
338
} ,
338
339
} ;
339
340
340
- const result = await executeTask ( task , { test : "data" } ) ;
341
+ const result = await executeTask ( task , { test : "data" } , undefined ) ;
341
342
342
343
// Verify hooks were called in correct order
343
344
expect ( globalFailureOrder ) . toEqual ( [ "global-1" , "global-2" , "task" ] ) ;
@@ -445,7 +446,7 @@ describe("TaskExecutor", () => {
445
446
} ,
446
447
} ;
447
448
448
- const result = await executeTask ( task , { test : "data" } ) ;
449
+ const result = await executeTask ( task , { test : "data" } , undefined ) ;
449
450
450
451
// Verify hooks were called in correct order
451
452
expect ( globalCompleteOrder ) . toEqual ( [ "global-1" , "global-2" , "task" ] ) ;
@@ -533,7 +534,7 @@ describe("TaskExecutor", () => {
533
534
} ,
534
535
} ;
535
536
536
- const result = await executeTask ( task , { test : "data" } ) ;
537
+ const result = await executeTask ( task , { test : "data" } , undefined ) ;
537
538
538
539
// Verify hooks were called in correct order
539
540
expect ( globalCompleteOrder ) . toEqual ( [ "global" , "task" ] ) ;
@@ -645,7 +646,7 @@ describe("TaskExecutor", () => {
645
646
} ,
646
647
} ;
647
648
648
- const result = await executeTask ( task , { test : "data" } ) ;
649
+ const result = await executeTask ( task , { test : "data" } , undefined ) ;
649
650
650
651
// Verify hooks were called in correct order and stopped after second global hook
651
652
expect ( hookCallOrder ) . toEqual ( [ "task" , "global-1" , "global-2" ] ) ;
@@ -707,7 +708,7 @@ describe("TaskExecutor", () => {
707
708
} ,
708
709
} ;
709
710
710
- const result = await executeTask ( task , { test : "data" } ) ;
711
+ const result = await executeTask ( task , { test : "data" } , undefined ) ;
711
712
712
713
// Verify only task hook was called
713
714
expect ( hookCallOrder ) . toEqual ( [ "task" ] ) ;
@@ -755,7 +756,7 @@ describe("TaskExecutor", () => {
755
756
} ,
756
757
} ;
757
758
758
- const result = await executeTask ( task , { test : "data" } ) ;
759
+ const result = await executeTask ( task , { test : "data" } , undefined ) ;
759
760
760
761
// Verify only task hook was called
761
762
expect ( hookCallOrder ) . toEqual ( [ "task" ] ) ;
@@ -863,7 +864,7 @@ describe("TaskExecutor", () => {
863
864
} ,
864
865
} ;
865
866
866
- const result = await executeTask ( task , { test : "data" } ) ;
867
+ const result = await executeTask ( task , { test : "data" } , undefined ) ;
867
868
868
869
// Verify the execution order:
869
870
// 1. Global middlewares (outside to inside)
@@ -935,7 +936,7 @@ describe("TaskExecutor", () => {
935
936
} ,
936
937
} ;
937
938
938
- const result = await executeTask ( task , { test : "data" } ) ;
939
+ const result = await executeTask ( task , { test : "data" } , undefined ) ;
939
940
940
941
// Verify only the middleware-before hook ran
941
942
expect ( executionOrder ) . toEqual ( [ "middleware-before" ] ) ;
@@ -1012,7 +1013,7 @@ describe("TaskExecutor", () => {
1012
1013
} ,
1013
1014
} ;
1014
1015
1015
- const result = await executeTask ( task , { test : "data" } ) ;
1016
+ const result = await executeTask ( task , { test : "data" } , undefined ) ;
1016
1017
1017
1018
// Verify only the global init hook ran, and failure/complete hooks were called
1018
1019
expect ( executionOrder ) . toEqual ( [ "global-init" , "failure" , "complete" ] ) ;
@@ -1094,7 +1095,7 @@ describe("TaskExecutor", () => {
1094
1095
} ,
1095
1096
} ;
1096
1097
1097
- const result = await executeTask ( task , { test : "data" } ) ;
1098
+ const result = await executeTask ( task , { test : "data" } , undefined ) ;
1098
1099
1099
1100
// Verify both init hooks ran, but run wasn't called, and failure/complete hooks were called
1100
1101
expect ( executionOrder ) . toEqual ( [ "global-init" , "task-init" , "failure" , "complete" ] ) ;
@@ -1184,7 +1185,7 @@ describe("TaskExecutor", () => {
1184
1185
} ,
1185
1186
} ;
1186
1187
1187
- const result = await executeTask ( task , { test : "data" } ) ;
1188
+ const result = await executeTask ( task , { test : "data" } , undefined ) ;
1188
1189
1189
1190
// Verify init succeeded, start hook failed, and run wasn't called
1190
1191
expect ( executionOrder ) . toEqual ( [ "global-init" , "global-start" , "failure" , "complete" ] ) ;
@@ -1295,7 +1296,7 @@ describe("TaskExecutor", () => {
1295
1296
} ,
1296
1297
} ;
1297
1298
1298
- const result = await executeTask ( task , { test : "data" } ) ;
1299
+ const result = await executeTask ( task , { test : "data" } , undefined ) ;
1299
1300
1300
1301
// Verify the execution order:
1301
1302
// 1. Middleware starts
@@ -1390,7 +1391,7 @@ describe("TaskExecutor", () => {
1390
1391
} ,
1391
1392
} ;
1392
1393
1393
- const result = await executeTask ( task , { test : "data" } ) ;
1394
+ const result = await executeTask ( task , { test : "data" } , undefined ) ;
1394
1395
1395
1396
// Verify cleanup hooks are called even after failure
1396
1397
expect ( executionOrder ) . toEqual ( [
@@ -1417,9 +1418,96 @@ describe("TaskExecutor", () => {
1417
1418
} ,
1418
1419
} ) ;
1419
1420
} ) ;
1421
+
1422
+ test ( "should handle max duration abort signal and call hooks in correct order" , async ( ) => {
1423
+ const executionOrder : string [ ] = [ ] ;
1424
+ const maxDurationMs = 1000 ;
1425
+
1426
+ // Create an abort controller that we'll trigger manually
1427
+ const controller = new AbortController ( ) ;
1428
+
1429
+ // Register global init hook
1430
+ lifecycleHooks . registerGlobalInitHook ( {
1431
+ id : "test-init" ,
1432
+ fn : async ( ) => {
1433
+ executionOrder . push ( "init" ) ;
1434
+ return {
1435
+ foo : "bar" ,
1436
+ } ;
1437
+ } ,
1438
+ } ) ;
1439
+
1440
+ // Register failure hook
1441
+ lifecycleHooks . registerGlobalFailureHook ( {
1442
+ id : "global-failure" ,
1443
+ fn : async ( { error } ) => {
1444
+ executionOrder . push ( "failure" ) ;
1445
+ expect ( ( error as Error ) . message ) . toBe (
1446
+ `Task execution exceeded maximum duration of ${ maxDurationMs } ms`
1447
+ ) ;
1448
+ } ,
1449
+ } ) ;
1450
+
1451
+ // Register complete hook
1452
+ lifecycleHooks . registerGlobalCompleteHook ( {
1453
+ id : "global-complete" ,
1454
+ fn : async ( { result } ) => {
1455
+ executionOrder . push ( "complete" ) ;
1456
+ expect ( result . ok ) . toBe ( false ) ;
1457
+ } ,
1458
+ } ) ;
1459
+
1460
+ // Register cleanup hook
1461
+ lifecycleHooks . registerGlobalCleanupHook ( {
1462
+ id : "global-cleanup" ,
1463
+ fn : async ( ) => {
1464
+ executionOrder . push ( "cleanup" ) ;
1465
+ } ,
1466
+ } ) ;
1467
+
1468
+ const task = {
1469
+ id : "test-task" ,
1470
+ fns : {
1471
+ run : async ( payload : any , params : RunFnParams < any > ) => {
1472
+ executionOrder . push ( "run-start" ) ;
1473
+
1474
+ // Create a promise that never resolves
1475
+ await new Promise ( ( resolve ) => {
1476
+ // Trigger abort after a small delay
1477
+ setTimeout ( ( ) => {
1478
+ controller . abort ( ) ;
1479
+ } , 10 ) ;
1480
+ } ) ;
1481
+
1482
+ // This should never be reached
1483
+ executionOrder . push ( "run-end" ) ;
1484
+ } ,
1485
+ } ,
1486
+ } ;
1487
+
1488
+ const result = await executeTask ( task , { test : "data" } , controller . signal ) ;
1489
+
1490
+ // Verify hooks were called in correct order
1491
+ expect ( executionOrder ) . toEqual ( [ "init" , "run-start" , "failure" , "complete" , "cleanup" ] ) ;
1492
+
1493
+ // Verify the error result
1494
+ expect ( result ) . toEqual ( {
1495
+ result : {
1496
+ ok : false ,
1497
+ id : "test-run-id" ,
1498
+ error : {
1499
+ type : "INTERNAL_ERROR" ,
1500
+ code : TaskRunErrorCodes . MAX_DURATION_EXCEEDED ,
1501
+ message : "Task execution exceeded maximum duration of 1000ms" ,
1502
+ stackTrace : expect . any ( String ) ,
1503
+ } ,
1504
+ skippedRetrying : false ,
1505
+ } ,
1506
+ } ) ;
1507
+ } ) ;
1420
1508
} ) ;
1421
1509
1422
- function executeTask ( task : TaskMetadataWithFunctions , payload : any ) {
1510
+ function executeTask ( task : TaskMetadataWithFunctions , payload : any , signal ?: AbortSignal ) {
1423
1511
const tracingSDK = new TracingSDK ( {
1424
1512
url : "http://localhost:4318" ,
1425
1513
} ) ;
@@ -1472,6 +1560,7 @@ function executeTask(task: TaskMetadataWithFunctions, payload: any) {
1472
1560
costInCents : 0 ,
1473
1561
baseCostInCents : 0 ,
1474
1562
priority : 0 ,
1563
+ maxDuration : 1000 ,
1475
1564
} ,
1476
1565
machine : {
1477
1566
name : "micro" ,
@@ -1508,5 +1597,5 @@ function executeTask(task: TaskMetadataWithFunctions, payload: any) {
1508
1597
engine : "V2" ,
1509
1598
} ;
1510
1599
1511
- return executor . execute ( execution , worker , { } ) ;
1600
+ return executor . execute ( execution , worker , { } , signal ) ;
1512
1601
}
0 commit comments