@@ -779,7 +779,8 @@ describe("TaskExecutor", () => {
779
779
} ,
780
780
} ) ;
781
781
782
- expect ( ( result as any ) . result . retry . delay ) . toBeCloseTo ( 30000 , - 1 ) ;
782
+ expect ( ( result as any ) . result . retry . delay ) . toBeGreaterThan ( 29900 ) ;
783
+ expect ( ( result as any ) . result . retry . delay ) . toBeLessThan ( 30100 ) ;
783
784
} ) ;
784
785
785
786
test ( "should execute middleware hooks in correct order around other hooks" , async ( ) => {
@@ -1203,6 +1204,219 @@ describe("TaskExecutor", () => {
1203
1204
} ,
1204
1205
} ) ;
1205
1206
} ) ;
1207
+
1208
+ test ( "should call cleanup hooks in correct order after other hooks but before middleware completion" , async ( ) => {
1209
+ const executionOrder : string [ ] = [ ] ;
1210
+
1211
+ // Register global init hook
1212
+ lifecycleHooks . registerGlobalInitHook ( {
1213
+ id : "test-init" ,
1214
+ fn : async ( ) => {
1215
+ executionOrder . push ( "init" ) ;
1216
+ return {
1217
+ foo : "bar" ,
1218
+ } ;
1219
+ } ,
1220
+ } ) ;
1221
+
1222
+ // Register global start hook
1223
+ lifecycleHooks . registerGlobalStartHook ( {
1224
+ id : "global-start" ,
1225
+ fn : async ( ) => {
1226
+ executionOrder . push ( "start" ) ;
1227
+ } ,
1228
+ } ) ;
1229
+
1230
+ // Register global success hook
1231
+ lifecycleHooks . registerGlobalSuccessHook ( {
1232
+ id : "global-success" ,
1233
+ fn : async ( ) => {
1234
+ executionOrder . push ( "success" ) ;
1235
+ } ,
1236
+ } ) ;
1237
+
1238
+ // Register global complete hook
1239
+ lifecycleHooks . registerGlobalCompleteHook ( {
1240
+ id : "global-complete" ,
1241
+ fn : async ( ) => {
1242
+ executionOrder . push ( "complete" ) ;
1243
+ } ,
1244
+ } ) ;
1245
+
1246
+ // Register global cleanup hooks
1247
+ lifecycleHooks . registerGlobalCleanupHook ( {
1248
+ id : "global-cleanup-1" ,
1249
+ fn : async ( { init } ) => {
1250
+ executionOrder . push ( "global-cleanup-1" ) ;
1251
+ // Verify we have access to init data
1252
+ expect ( init ) . toEqual ( { foo : "bar" } ) ;
1253
+ } ,
1254
+ } ) ;
1255
+
1256
+ lifecycleHooks . registerGlobalCleanupHook ( {
1257
+ id : "global-cleanup-2" ,
1258
+ fn : async ( { init } ) => {
1259
+ executionOrder . push ( "global-cleanup-2" ) ;
1260
+ // Verify we have access to init data
1261
+ expect ( init ) . toEqual ( { foo : "bar" } ) ;
1262
+ } ,
1263
+ } ) ;
1264
+
1265
+ // Register task-specific cleanup hook
1266
+ lifecycleHooks . registerTaskCleanupHook ( "test-task" , {
1267
+ id : "task-cleanup" ,
1268
+ fn : async ( { init } ) => {
1269
+ executionOrder . push ( "task-cleanup" ) ;
1270
+ // Verify we have access to init data
1271
+ expect ( init ) . toEqual ( { foo : "bar" } ) ;
1272
+ } ,
1273
+ } ) ;
1274
+
1275
+ // Register middleware to verify cleanup happens before middleware completion
1276
+ lifecycleHooks . registerGlobalMiddlewareHook ( {
1277
+ id : "global-middleware" ,
1278
+ fn : async ( { next } ) => {
1279
+ executionOrder . push ( "middleware-before" ) ;
1280
+ await next ( ) ;
1281
+ executionOrder . push ( "middleware-after" ) ;
1282
+ } ,
1283
+ } ) ;
1284
+
1285
+ const task = {
1286
+ id : "test-task" ,
1287
+ fns : {
1288
+ run : async ( payload : any , params : RunFnParams < any > ) => {
1289
+ executionOrder . push ( "run" ) ;
1290
+ return {
1291
+ output : "test-output" ,
1292
+ init : params . init ,
1293
+ } ;
1294
+ } ,
1295
+ } ,
1296
+ } ;
1297
+
1298
+ const result = await executeTask ( task , { test : "data" } ) ;
1299
+
1300
+ // Verify the execution order:
1301
+ // 1. Middleware starts
1302
+ // 2. Init hook
1303
+ // 3. Start hook
1304
+ // 4. Run function
1305
+ // 5. Success hook
1306
+ // 6. Complete hook
1307
+ // 7. Cleanup hooks
1308
+ // 8. Middleware completes
1309
+ expect ( executionOrder ) . toEqual ( [
1310
+ "middleware-before" ,
1311
+ "init" ,
1312
+ "start" ,
1313
+ "run" ,
1314
+ "success" ,
1315
+ "complete" ,
1316
+ "global-cleanup-1" ,
1317
+ "global-cleanup-2" ,
1318
+ "task-cleanup" ,
1319
+ "middleware-after" ,
1320
+ ] ) ;
1321
+
1322
+ // Verify the final result
1323
+ expect ( result ) . toEqual ( {
1324
+ result : {
1325
+ ok : true ,
1326
+ id : "test-run-id" ,
1327
+ output : '{"json":{"output":"test-output","init":{"foo":"bar"}}}' ,
1328
+ outputType : "application/super+json" ,
1329
+ } ,
1330
+ } ) ;
1331
+ } ) ;
1332
+
1333
+ test ( "should call cleanup hooks even when task fails" , async ( ) => {
1334
+ const executionOrder : string [ ] = [ ] ;
1335
+ const expectedError = new Error ( "Task failed intentionally" ) ;
1336
+
1337
+ // Register global init hook
1338
+ lifecycleHooks . registerGlobalInitHook ( {
1339
+ id : "test-init" ,
1340
+ fn : async ( ) => {
1341
+ executionOrder . push ( "init" ) ;
1342
+ return {
1343
+ foo : "bar" ,
1344
+ } ;
1345
+ } ,
1346
+ } ) ;
1347
+
1348
+ // Register failure hook
1349
+ lifecycleHooks . registerGlobalFailureHook ( {
1350
+ id : "global-failure" ,
1351
+ fn : async ( ) => {
1352
+ executionOrder . push ( "failure" ) ;
1353
+ } ,
1354
+ } ) ;
1355
+
1356
+ // Register complete hook
1357
+ lifecycleHooks . registerGlobalCompleteHook ( {
1358
+ id : "global-complete" ,
1359
+ fn : async ( ) => {
1360
+ executionOrder . push ( "complete" ) ;
1361
+ } ,
1362
+ } ) ;
1363
+
1364
+ // Register cleanup hooks
1365
+ lifecycleHooks . registerGlobalCleanupHook ( {
1366
+ id : "global-cleanup" ,
1367
+ fn : async ( { init } ) => {
1368
+ executionOrder . push ( "global-cleanup" ) ;
1369
+ // Verify we have access to init data even after failure
1370
+ expect ( init ) . toEqual ( { foo : "bar" } ) ;
1371
+ } ,
1372
+ } ) ;
1373
+
1374
+ lifecycleHooks . registerTaskCleanupHook ( "test-task" , {
1375
+ id : "task-cleanup" ,
1376
+ fn : async ( { init } ) => {
1377
+ executionOrder . push ( "task-cleanup" ) ;
1378
+ // Verify we have access to init data even after failure
1379
+ expect ( init ) . toEqual ( { foo : "bar" } ) ;
1380
+ } ,
1381
+ } ) ;
1382
+
1383
+ const task = {
1384
+ id : "test-task" ,
1385
+ fns : {
1386
+ run : async ( ) => {
1387
+ executionOrder . push ( "run" ) ;
1388
+ throw expectedError ;
1389
+ } ,
1390
+ } ,
1391
+ } ;
1392
+
1393
+ const result = await executeTask ( task , { test : "data" } ) ;
1394
+
1395
+ // Verify cleanup hooks are called even after failure
1396
+ expect ( executionOrder ) . toEqual ( [
1397
+ "init" ,
1398
+ "run" ,
1399
+ "failure" ,
1400
+ "complete" ,
1401
+ "global-cleanup" ,
1402
+ "task-cleanup" ,
1403
+ ] ) ;
1404
+
1405
+ // Verify the error result
1406
+ expect ( result ) . toEqual ( {
1407
+ result : {
1408
+ ok : false ,
1409
+ id : "test-run-id" ,
1410
+ error : {
1411
+ type : "BUILT_IN_ERROR" ,
1412
+ message : "Task failed intentionally" ,
1413
+ name : "Error" ,
1414
+ stackTrace : expect . any ( String ) ,
1415
+ } ,
1416
+ skippedRetrying : false ,
1417
+ } ,
1418
+ } ) ;
1419
+ } ) ;
1206
1420
} ) ;
1207
1421
1208
1422
function executeTask ( task : TaskMetadataWithFunctions , payload : any ) {
0 commit comments