@@ -953,6 +953,256 @@ describe("TaskExecutor", () => {
953
953
} ,
954
954
} ) ;
955
955
} ) ;
956
+
957
+ test ( "should propagate errors from init hooks" , async ( ) => {
958
+ const executionOrder : string [ ] = [ ] ;
959
+ const expectedError = new Error ( "Init hook error" ) ;
960
+
961
+ // Register global init hook that throws an error
962
+ lifecycleHooks . registerGlobalInitHook ( {
963
+ id : "failing-init" ,
964
+ fn : async ( ) => {
965
+ executionOrder . push ( "global-init" ) ;
966
+ throw expectedError ;
967
+ } ,
968
+ } ) ;
969
+
970
+ // Register task init hook that should never be called
971
+ lifecycleHooks . registerTaskInitHook ( "test-task" , {
972
+ id : "task-init" ,
973
+ fn : async ( ) => {
974
+ executionOrder . push ( "task-init" ) ;
975
+ return {
976
+ foo : "bar" ,
977
+ } ;
978
+ } ,
979
+ } ) ;
980
+
981
+ // Register failure hook to verify it's called
982
+ lifecycleHooks . registerGlobalFailureHook ( {
983
+ id : "global-failure" ,
984
+ fn : async ( { error } ) => {
985
+ executionOrder . push ( "failure" ) ;
986
+ expect ( error ) . toBe ( expectedError ) ;
987
+ } ,
988
+ } ) ;
989
+
990
+ // Register complete hook to verify it's called with error
991
+ lifecycleHooks . registerGlobalCompleteHook ( {
992
+ id : "global-complete" ,
993
+ fn : async ( { result } ) => {
994
+ executionOrder . push ( "complete" ) ;
995
+ expect ( result ) . toEqual ( {
996
+ ok : false ,
997
+ error : expectedError ,
998
+ } ) ;
999
+ } ,
1000
+ } ) ;
1001
+
1002
+ const task = {
1003
+ id : "test-task" ,
1004
+ fns : {
1005
+ run : async ( payload : any , params : RunFnParams < any > ) => {
1006
+ executionOrder . push ( "run" ) ;
1007
+ return {
1008
+ output : "test-output" ,
1009
+ } ;
1010
+ } ,
1011
+ } ,
1012
+ } ;
1013
+
1014
+ const result = await executeTask ( task , { test : "data" } ) ;
1015
+
1016
+ // Verify only the global init hook ran, and failure/complete hooks were called
1017
+ expect ( executionOrder ) . toEqual ( [ "global-init" , "failure" , "complete" ] ) ;
1018
+
1019
+ // Verify the error result
1020
+ expect ( result ) . toEqual ( {
1021
+ result : {
1022
+ ok : false ,
1023
+ id : "test-run-id" ,
1024
+ error : {
1025
+ type : "BUILT_IN_ERROR" ,
1026
+ message : "Init hook error" ,
1027
+ name : "Error" ,
1028
+ stackTrace : expect . any ( String ) ,
1029
+ } ,
1030
+ skippedRetrying : false ,
1031
+ } ,
1032
+ } ) ;
1033
+ } ) ;
1034
+
1035
+ test ( "should propagate errors from task init hooks" , async ( ) => {
1036
+ const executionOrder : string [ ] = [ ] ;
1037
+ const expectedError = new Error ( "Task init hook error" ) ;
1038
+
1039
+ // Register global init hook that succeeds
1040
+ lifecycleHooks . registerGlobalInitHook ( {
1041
+ id : "global-init" ,
1042
+ fn : async ( ) => {
1043
+ executionOrder . push ( "global-init" ) ;
1044
+ return {
1045
+ foo : "bar" ,
1046
+ } ;
1047
+ } ,
1048
+ } ) ;
1049
+
1050
+ // Register task init hook that throws an error
1051
+ lifecycleHooks . registerTaskInitHook ( "test-task" , {
1052
+ id : "task-init" ,
1053
+ fn : async ( ) => {
1054
+ executionOrder . push ( "task-init" ) ;
1055
+ throw expectedError ;
1056
+ } ,
1057
+ } ) ;
1058
+
1059
+ // Register failure hook to verify it's called
1060
+ lifecycleHooks . registerGlobalFailureHook ( {
1061
+ id : "global-failure" ,
1062
+ fn : async ( { error, init } ) => {
1063
+ executionOrder . push ( "failure" ) ;
1064
+ expect ( error ) . toBe ( expectedError ) ;
1065
+ // Verify we got the global init data
1066
+ expect ( init ) . toEqual ( { foo : "bar" } ) ;
1067
+ } ,
1068
+ } ) ;
1069
+
1070
+ // Register complete hook to verify it's called with error
1071
+ lifecycleHooks . registerGlobalCompleteHook ( {
1072
+ id : "global-complete" ,
1073
+ fn : async ( { result, init } ) => {
1074
+ executionOrder . push ( "complete" ) ;
1075
+ expect ( result ) . toEqual ( {
1076
+ ok : false ,
1077
+ error : expectedError ,
1078
+ } ) ;
1079
+ // Verify we got the global init data
1080
+ expect ( init ) . toEqual ( { foo : "bar" } ) ;
1081
+ } ,
1082
+ } ) ;
1083
+
1084
+ const task = {
1085
+ id : "test-task" ,
1086
+ fns : {
1087
+ run : async ( payload : any , params : RunFnParams < any > ) => {
1088
+ executionOrder . push ( "run" ) ;
1089
+ return {
1090
+ output : "test-output" ,
1091
+ } ;
1092
+ } ,
1093
+ } ,
1094
+ } ;
1095
+
1096
+ const result = await executeTask ( task , { test : "data" } ) ;
1097
+
1098
+ // Verify both init hooks ran, but run wasn't called, and failure/complete hooks were called
1099
+ expect ( executionOrder ) . toEqual ( [ "global-init" , "task-init" , "failure" , "complete" ] ) ;
1100
+
1101
+ // Verify the error result
1102
+ expect ( result ) . toEqual ( {
1103
+ result : {
1104
+ ok : false ,
1105
+ id : "test-run-id" ,
1106
+ error : {
1107
+ type : "BUILT_IN_ERROR" ,
1108
+ message : "Task init hook error" ,
1109
+ name : "Error" ,
1110
+ stackTrace : expect . any ( String ) ,
1111
+ } ,
1112
+ skippedRetrying : false ,
1113
+ } ,
1114
+ } ) ;
1115
+ } ) ;
1116
+
1117
+ test ( "should propagate errors from start hooks" , async ( ) => {
1118
+ const executionOrder : string [ ] = [ ] ;
1119
+ const expectedError = new Error ( "Start hook error" ) ;
1120
+
1121
+ // Register global init hook that succeeds
1122
+ lifecycleHooks . registerGlobalInitHook ( {
1123
+ id : "global-init" ,
1124
+ fn : async ( ) => {
1125
+ executionOrder . push ( "global-init" ) ;
1126
+ return {
1127
+ foo : "bar" ,
1128
+ } ;
1129
+ } ,
1130
+ } ) ;
1131
+
1132
+ // Register global start hook that throws an error
1133
+ lifecycleHooks . registerGlobalStartHook ( {
1134
+ id : "global-start" ,
1135
+ fn : async ( ) => {
1136
+ executionOrder . push ( "global-start" ) ;
1137
+ throw expectedError ;
1138
+ } ,
1139
+ } ) ;
1140
+
1141
+ // Register task start hook that should never be called
1142
+ lifecycleHooks . registerTaskStartHook ( "test-task" , {
1143
+ id : "task-start" ,
1144
+ fn : async ( ) => {
1145
+ executionOrder . push ( "task-start" ) ;
1146
+ } ,
1147
+ } ) ;
1148
+
1149
+ // Register failure hook to verify it's called
1150
+ lifecycleHooks . registerGlobalFailureHook ( {
1151
+ id : "global-failure" ,
1152
+ fn : async ( { error, init } ) => {
1153
+ executionOrder . push ( "failure" ) ;
1154
+ expect ( error ) . toBe ( expectedError ) ;
1155
+ // Verify we got the init data
1156
+ expect ( init ) . toEqual ( { foo : "bar" } ) ;
1157
+ } ,
1158
+ } ) ;
1159
+
1160
+ // Register complete hook to verify it's called with error
1161
+ lifecycleHooks . registerGlobalCompleteHook ( {
1162
+ id : "global-complete" ,
1163
+ fn : async ( { result, init } ) => {
1164
+ executionOrder . push ( "complete" ) ;
1165
+ expect ( result ) . toEqual ( {
1166
+ ok : false ,
1167
+ error : expectedError ,
1168
+ } ) ;
1169
+ // Verify we got the init data
1170
+ expect ( init ) . toEqual ( { foo : "bar" } ) ;
1171
+ } ,
1172
+ } ) ;
1173
+
1174
+ const task = {
1175
+ id : "test-task" ,
1176
+ fns : {
1177
+ run : async ( payload : any , params : RunFnParams < any > ) => {
1178
+ executionOrder . push ( "run" ) ;
1179
+ return {
1180
+ output : "test-output" ,
1181
+ } ;
1182
+ } ,
1183
+ } ,
1184
+ } ;
1185
+
1186
+ const result = await executeTask ( task , { test : "data" } ) ;
1187
+
1188
+ // Verify init succeeded, start hook failed, and run wasn't called
1189
+ expect ( executionOrder ) . toEqual ( [ "global-init" , "global-start" , "failure" , "complete" ] ) ;
1190
+
1191
+ // Verify the error result
1192
+ expect ( result ) . toEqual ( {
1193
+ result : {
1194
+ ok : false ,
1195
+ id : "test-run-id" ,
1196
+ error : {
1197
+ type : "BUILT_IN_ERROR" ,
1198
+ message : "Start hook error" ,
1199
+ name : "Error" ,
1200
+ stackTrace : expect . any ( String ) ,
1201
+ } ,
1202
+ skippedRetrying : false ,
1203
+ } ,
1204
+ } ) ;
1205
+ } ) ;
956
1206
} ) ;
957
1207
958
1208
function executeTask ( task : TaskMetadataWithFunctions , payload : any ) {
0 commit comments