38
38
WorkflowHandle ,
39
39
)
40
40
from temporalio .common import WorkflowIDConflictPolicy
41
- from temporalio .exceptions import CancelledError , NexusOperationError
41
+ from temporalio .exceptions import ApplicationError , CancelledError , NexusOperationError
42
42
from temporalio .nexus import WorkflowRunOperationContext , workflow_run_operation
43
43
from temporalio .service import RPCError , RPCStatusCode
44
44
from temporalio .worker import Worker
@@ -1087,8 +1087,134 @@ async def assert_handler_workflow_has_link_to_caller_workflow(
1087
1087
1088
1088
# Handler
1089
1089
1090
+ # @OperationImpl
1091
+ # public OperationHandler<NexusService.ErrorTestInput, NexusService.ErrorTestOutput> testError() {
1092
+ # return OperationHandler.sync(
1093
+ # (ctx, details, input) -> {
1094
+ # switch (input.getAction()) {
1095
+ # case RAISE_APPLICATION_ERROR:
1096
+ # throw ApplicationFailure.newNonRetryableFailure(
1097
+ # "application error 1", "APPLICATION_ERROR");
1098
+ # case RAISE_CUSTOM_ERROR:
1099
+ # throw new MyCustomException("Custom error 1");
1100
+ # case RAISE_CUSTOM_ERROR_WITH_CAUSE_OF_CUSTOM_ERROR:
1101
+ # // ** THIS DOESN'T WORK **: CHAINED CUSTOM EXCEPTIONS DON'T SERIALIZE
1102
+ # MyCustomException customError = new MyCustomException("Custom error 1");
1103
+ # customError.initCause(new MyCustomException("Custom error 2"));
1104
+ # throw customError;
1105
+ # case RAISE_APPLICATION_ERROR_WITH_CAUSE_OF_CUSTOM_ERROR:
1106
+ # throw ApplicationFailure.newNonRetryableFailureWithCause(
1107
+ # "application error 1",
1108
+ # "APPLICATION_ERROR",
1109
+ # new MyCustomException("Custom error 2"));
1110
+ # case RAISE_NEXUS_HANDLER_ERROR:
1111
+ # throw new HandlerException(HandlerException.ErrorType.NOT_FOUND, "Handler error 1");
1112
+ # case RAISE_NEXUS_HANDLER_ERROR_WITH_CAUSE_OF_CUSTOM_ERROR:
1113
+ # // ** THIS DOESN'T WORK **
1114
+ # // Can't overwrite cause with
1115
+ # // io.temporal.samples.nexus.handler.NexusServiceImpl$MyCustomException: Custom error
1116
+ # // 2
1117
+ # HandlerException handlerErr =
1118
+ # new HandlerException(HandlerException.ErrorType.NOT_FOUND, "Handler error 1");
1119
+ # handlerErr.initCause(new MyCustomException("Custom error 2"));
1120
+ # throw handlerErr;
1121
+ # case RAISE_NEXUS_OPERATION_ERROR_WITH_CAUSE_OF_CUSTOM_ERROR:
1122
+ # throw OperationException.failure(
1123
+ # ApplicationFailure.newNonRetryableFailureWithCause(
1124
+ # "application error 1",
1125
+ # "APPLICATION_ERROR",
1126
+ # new MyCustomException("Custom error 2")));
1127
+ # }
1128
+ # return new NexusService.ErrorTestOutput("Unreachable");
1129
+ # });
1130
+ # }
1131
+
1132
+ # 🌈 RAISE_APPLICATION_ERROR:
1133
+ # io.temporal.failure.NexusOperationFailure(type=no-type-attr, message=Nexus Operation with operation='testErrorservice='NexusService' endpoint='my-nexus-endpoint-name' failed: 'nexus operation completed unsuccessfully'. scheduledEventId=5, operationToken=)
1134
+ # io.nexusrpc.handler.HandlerException(type=no-type-attr, message=handler error: message='application error 1', type='APPLICATION_ERROR', nonRetryable=true)
1135
+ # io.temporal.failure.ApplicationFailure(type=no-type-attr, message=message='application error 1', type='APPLICATION_ERROR', nonRetryable=true)
1136
+
1137
+
1138
+ # 🌈 RAISE_CUSTOM_ERROR:
1139
+ # io.temporal.failure.NexusOperationFailure(type=no-type-attr, message=Nexus Operation with operation='testErrorservice='NexusService' endpoint='my-nexus-endpoint-name' failed: 'nexus operation completed unsuccessfully'. scheduledEventId=5, operationToken=)
1140
+ # io.nexusrpc.handler.HandlerException(type=no-type-attr, message=handler error: message='Custom error wrapped: custom error 1', type='CUSTOM_ERROR', nonRetryable=true)
1141
+ # io.temporal.failure.ApplicationFailure(type=no-type-attr, message=message='Custom error wrapped: custom error 1', type='CUSTOM_ERROR', nonRetryable=true)
1142
+
1143
+
1144
+ # 🌈 RAISE_APPLICATION_ERROR_WITH_CAUSE_OF_CUSTOM_ERROR:
1145
+ # io.temporal.failure.NexusOperationFailure(type=no-type-attr, message=Nexus Operation with operation='testErrorservice='NexusService' endpoint='my-nexus-endpoint-name' failed: 'nexus operation completed unsuccessfully'. scheduledEventId=5, operationToken=)
1146
+ # io.nexusrpc.handler.HandlerException(type=no-type-attr, message=handler error: message='application error 1', type='APPLICATION_ERROR', nonRetryable=true)
1147
+ # io.temporal.failure.ApplicationFailure(type=no-type-attr, message=message='application error 1', type='APPLICATION_ERROR', nonRetryable=true)
1148
+ # io.temporal.failure.ApplicationFailure(type=no-type-attr, message=message='Custom error 2', type='io.temporal.samples.nexus.handler.NexusServiceImpl$MyCustomException', nonRetryable=false)
1149
+
1150
+
1151
+ # 🌈 RAISE_NEXUS_HANDLER_ERROR:
1152
+ # io.temporal.failure.NexusOperationFailure(type=no-type-attr, message=Nexus Operation with operation='testErrorservice='NexusService' endpoint='my-nexus-endpoint-name' failed: 'nexus operation completed unsuccessfully'. scheduledEventId=5, operationToken=)
1153
+ # io.nexusrpc.handler.HandlerException(type=no-type-attr, message=handler error: message='Handler error 1', type='java.lang.RuntimeException', nonRetryable=false)
1154
+ # io.temporal.failure.ApplicationFailure(type=no-type-attr, message=message='Handler error 1', type='java.lang.RuntimeException', nonRetryable=false)
1155
+
1156
+
1157
+ # 🌈 RAISE_NEXUS_HANDLER_ERROR_WITH_CAUSE_OF_CUSTOM_ERROR:
1158
+ # io.temporal.failure.NexusOperationFailure(type=no-type-attr, message=Nexus Operation with operation='testErrorservice='NexusService' endpoint='my-nexus-endpoint-name' failed: 'nexus operation completed unsuccessfully'. scheduledEventId=5, operationToken=)
1159
+ # io.temporal.failure.TimeoutFailure(type=no-type-attr, message=message='operation timed out', timeoutType=TIMEOUT_TYPE_SCHEDULE_TO_CLOSE)
1160
+
1161
+
1162
+ # 🌈 RAISE_NEXUS_OPERATION_ERROR_WITH_CAUSE_OF_CUSTOM_ERROR:
1163
+ # io.temporal.failure.NexusOperationFailure(type=no-type-attr, message=Nexus Operation with operation='testErrorservice='NexusService' endpoint='my-nexus-endpoint-name' failed: 'nexus operation completed unsuccessfully'. scheduledEventId=5, operationToken=)
1164
+ # io.temporal.failure.ApplicationFailure(type=no-type-attr, message=message='application error 1', type='APPLICATION_ERROR', nonRetryable=true)
1165
+ # io.temporal.failure.ApplicationFailure(type=no-type-attr, message=message='Custom error 2', type='io.temporal.samples.nexus.handler.NexusServiceImpl$MyCustomException', nonRetryable=false)
1166
+
1167
+ # @OperationImpl
1168
+ # public OperationHandler<NexusService.ErrorTestInput, NexusService.ErrorTestOutput> testError() {
1169
+ # return OperationHandler.sync(
1170
+ # (ctx, details, input) -> {
1171
+ # switch (input.getAction()) {
1172
+ # case RAISE_APPLICATION_ERROR:
1173
+ # throw ApplicationFailure.newNonRetryableFailure(
1174
+ # "application error 1", "APPLICATION_ERROR");
1175
+ # case RAISE_CUSTOM_ERROR:
1176
+ # throw new MyCustomException("Custom error 1");
1177
+ # case RAISE_CUSTOM_ERROR_WITH_CAUSE_OF_CUSTOM_ERROR:
1178
+ # // ** THIS DOESN'T WORK **: CHAINED CUSTOM EXCEPTIONS DON'T SERIALIZE
1179
+ # MyCustomException customError = new MyCustomException("Custom error 1");
1180
+ # customError.initCause(new MyCustomException("Custom error 2"));
1181
+ # throw customError;
1182
+ # case RAISE_APPLICATION_ERROR_WITH_CAUSE_OF_CUSTOM_ERROR:
1183
+ # throw ApplicationFailure.newNonRetryableFailureWithCause(
1184
+ # "application error 1",
1185
+ # "APPLICATION_ERROR",
1186
+ # new MyCustomException("Custom error 2"));
1187
+ # case RAISE_NEXUS_HANDLER_ERROR:
1188
+ # throw new HandlerException(HandlerException.ErrorType.NOT_FOUND, "Handler error 1");
1189
+ # case RAISE_NEXUS_HANDLER_ERROR_WITH_CAUSE_OF_CUSTOM_ERROR:
1190
+ # // ** THIS DOESN'T WORK **
1191
+ # // Can't overwrite cause with
1192
+ # // io.temporal.samples.nexus.handler.NexusServiceImpl$MyCustomException: Custom error
1193
+ # // 2
1194
+ # HandlerException handlerErr =
1195
+ # new HandlerException(HandlerException.ErrorType.NOT_FOUND, "Handler error 1");
1196
+ # handlerErr.initCause(new MyCustomException("Custom error 2"));
1197
+ # throw handlerErr;
1198
+ # case RAISE_NEXUS_OPERATION_ERROR_WITH_CAUSE_OF_CUSTOM_ERROR:
1199
+ # throw OperationException.failure(
1200
+ # ApplicationFailure.newNonRetryableFailureWithCause(
1201
+ # "application error 1",
1202
+ # "APPLICATION_ERROR",
1203
+ # new MyCustomException("Custom error 2")));
1204
+ # }
1205
+ # return new NexusService.ErrorTestOutput("Unreachable");
1206
+ # });
1207
+ # }
1208
+
1209
+
1090
1210
ActionInSyncOp = Literal [
1091
- "raise_handler_error" , "raise_operation_error" , "raise_custom_error"
1211
+ "application_error_non_retryable" ,
1212
+ "custom_error" ,
1213
+ "custom_error_from_custom_error" ,
1214
+ "application_error_non_retryable_from_custom_error" ,
1215
+ "nexus_handler_error_not_found" ,
1216
+ "nexus_handler_error_not_found_from_custom_error" ,
1217
+ "nexus_operation_error_from_application_error_non_retryable_from_custom_error" ,
1092
1218
]
1093
1219
1094
1220
@@ -1106,17 +1232,46 @@ class ErrorTestInput:
1106
1232
class ErrorTestService :
1107
1233
@sync_operation
1108
1234
async def op (self , ctx : StartOperationContext , input : ErrorTestInput ) -> None :
1109
- if input .action_in_sync_op == "raise_handler_error" :
1235
+ if input .action_in_sync_op == "application_error_non_retryable" :
1236
+ raise ApplicationError ("application error in nexus op" , non_retryable = True )
1237
+ elif input .action_in_sync_op == "custom_error" :
1238
+ raise CustomError ("custom error in nexus op" )
1239
+ elif input .action_in_sync_op == "custom_error_from_custom_error" :
1240
+ raise CustomError ("custom error 1 in nexus op" ) from CustomError (
1241
+ "custom error 2 in nexus op"
1242
+ )
1243
+ elif (
1244
+ input .action_in_sync_op
1245
+ == "application_error_non_retryable_from_custom_error"
1246
+ ):
1247
+ raise ApplicationError (
1248
+ "application error in nexus op" , non_retryable = True
1249
+ ) from CustomError ("custom error in nexus op" )
1250
+ elif input .action_in_sync_op == "nexus_handler_error_not_found" :
1110
1251
raise nexusrpc .HandlerError (
1111
1252
"test" ,
1112
- type = nexusrpc .HandlerErrorType .INTERNAL ,
1253
+ type = nexusrpc .HandlerErrorType .NOT_FOUND ,
1113
1254
)
1114
- elif input .action_in_sync_op == "raise_operation_error" :
1115
- raise nexusrpc .OperationError (
1116
- "test" , state = nexusrpc .OperationErrorState .FAILED
1117
- )
1118
- elif input .action_in_sync_op == "raise_custom_error" :
1119
- raise CustomError ("test" )
1255
+ elif (
1256
+ input .action_in_sync_op == "nexus_handler_error_not_found_from_custom_error"
1257
+ ):
1258
+ raise nexusrpc .HandlerError (
1259
+ "test" ,
1260
+ type = nexusrpc .HandlerErrorType .NOT_FOUND ,
1261
+ ) from CustomError ("custom error in nexus op" )
1262
+ elif (
1263
+ input .action_in_sync_op
1264
+ == "nexus_operation_error_from_application_error_non_retryable_from_custom_error"
1265
+ ):
1266
+ try :
1267
+ raise ApplicationError (
1268
+ "application error in nexus op" , non_retryable = True
1269
+ ) from CustomError ("custom error in nexus op" )
1270
+ except ApplicationError as err :
1271
+ raise nexusrpc .OperationError (
1272
+ "operation error in nexus op" ,
1273
+ state = nexusrpc .OperationErrorState .FAILED ,
1274
+ ) from err
1120
1275
else :
1121
1276
raise NotImplementedError (
1122
1277
f"Unhandled action_in_sync_op: { input .action_in_sync_op } "
@@ -1146,14 +1301,26 @@ async def run(self, input: ErrorTestInput) -> list[str]:
1146
1301
# None
1147
1302
input ,
1148
1303
)
1149
- except Exception as err :
1150
- return [str (type (err ).__name__ ), str (type (err .__cause__ ).__name__ )]
1304
+ except BaseException as err :
1305
+ errs = [err ]
1306
+ while err .__cause__ :
1307
+ errs .append (err .__cause__ )
1308
+ err = err .__cause__
1309
+ return [type (err ).__name__ for err in errs ]
1151
1310
assert False , "Unreachable"
1152
1311
1153
1312
1154
1313
@pytest .mark .parametrize (
1155
1314
"action_in_sync_op" ,
1156
- ["raise_handler_error" , "raise_operation_error" , "raise_custom_error" ],
1315
+ [
1316
+ "application_error_non_retryable" ,
1317
+ "custom_error" ,
1318
+ "custom_error_from_custom_error" ,
1319
+ "application_error_non_retryable_from_custom_error" ,
1320
+ "nexus_handler_error_not_found" ,
1321
+ "nexus_handler_error_not_found_from_custom_error" ,
1322
+ "nexus_operation_error_from_application_error_non_retryable_from_custom_error" ,
1323
+ ],
1157
1324
)
1158
1325
async def test_errors_raised_by_nexus_operation (
1159
1326
client : Client , action_in_sync_op : ActionInSyncOp
@@ -1178,14 +1345,14 @@ async def test_errors_raised_by_nexus_operation(
1178
1345
1179
1346
print (f"\n \n \n { action_in_sync_op } : \n " , result , "\n \n \n " )
1180
1347
1181
- if action_in_sync_op == "raise_handler_error " :
1182
- assert result == ["NexusOperationError" , "HandlerError" ]
1183
- elif action_in_sync_op == "raise_operation_error " :
1184
- assert result == ["NexusOperationError" , "ApplicationError" ]
1185
- elif action_in_sync_op == "raise_custom_error " :
1186
- # assert result == ["NexusOperationError", "CustomError"]
1187
- pass
1188
- else :
1189
- raise NotImplementedError (
1190
- f"Unhandled action_in_sync_op: { action_in_sync_op } "
1191
- )
1348
+ # if action_in_sync_op == "handler_error ":
1349
+ # assert result == ["NexusOperationError", "HandlerError"]
1350
+ # elif action_in_sync_op == "operation_error ":
1351
+ # assert result == ["NexusOperationError", "ApplicationError"]
1352
+ # elif action_in_sync_op == "custom_error ":
1353
+ # # assert result == ["NexusOperationError", "CustomError"]
1354
+ # pass
1355
+ # else:
1356
+ # raise NotImplementedError(
1357
+ # f"Unhandled action_in_sync_op: {action_in_sync_op}"
1358
+ # )
0 commit comments