quarkus: Quarkus Reactive Mutiny - Composite Exception encapsulation on Runtime Exceptions and @ExceptionHandler

Description

I am evaluating quarkus 1.6 and reactive Mutiny for reactive routes. My experience with quarkus mutiny exception handling is not so great . The current problem I have is if I throw a RuntimeException down in the service layer or data layer . The exception gets encapsulated as a CompositeException with a list of causes where one of the causes is the the RuntimeException thrown. This means that I have to always Parse the CompositeException to retrieve the actual exception which I have thrown to determine the HTTP status response ( of whether to throw a 500 or 422 or something else) .

Code Snippet - Current :

return Uni.createFrom().item(getRequest).flatMap(request ->{
  log.info("Request Received successfully {}", kv("someRequest", request));
  return xyzService.get(request, transactionContext);
}).onItemOrFailure().apply((paList, throwable) ->{
  if (paList != null) {
    return Response.ok(somePOJO).build();
  }

  if (throwable != null) {
    if (throwable instanceof CompositeException) {
      CompositeException compositeException = (CompositeException) throwable;
      Optional < Throwable > exception = isExceptionInstanceOf(compositeException, XYZRuntimeException.class);
      if (exception.isPresent()) {
        return Response.serverError().status(500).entity(somePOJO).build();
      }
    }

    if (throwable instanceof CircuitBreakerOpenException) {
      return Response.serverError().status(500).entity(somePOJO).build();

    }
  }

  return Response.serverError().status(500).entity(somePOJO).build();

});

Code Snippet - Expected :


//Controller logic 
return Uni.createFrom().item(getRequest)
                .flatMap(request -> {
                    log.info("Request Received successfully {}", kv("someRequest", request));
                    return xyzService.get(request, transactionContext);
                })
                .onItem()
                .apply(paList -> {
                    if (paList != null) {
                        return Response.ok(somePOJO)
                                .build();
                    }

                   return Response.serverError()
                            .status(500)
                            .entity(somePOJO)
                            .build();

                });

//Exception Handler can be in the same class or a different class ( different class will be annotated as @ControllerAdvice)
@ExceptionHandler
public Uni<Response> handleXYZException(XYZRuntimeException exception, <<FrameworkContextObject>> obj){
   
                                return Response.serverError()
                                        .status(500)
                                        .entity(somePOJO)
                            .build();
     
}

Implementation ideas

Can we have something similar to spring webflux , where if a RuntimeException is thrown from the data layer

a) Exactly same exception is captured in the error block of the controller class without needing to parse an encapsulated exception .

b) The Spring Boot framework has a @ControllerAdvice and @ExceptionHandler annotations to cleanly segregating the class for handling exceptions and controller. Can the same be available for Quarkus Reactive Mutiny extension.

c) The Spring boot framework has ServerWebExchange object which we can use as a context object to pass custom context . The good thing of this serverwebExchange object is that it is injected automatically as part of @ExceptionHandler Method making it easy to pass Context objects to exception handling methods . Can we have something similar in quarkus / reactive mutiny ?

(If you have any implementation ideas, they can go here, however please note that all design change proposals should be posted to the Quarkus developer mailing list (or the corresponding Google Group; see the decisions process document for more information).

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 22 (11 by maintainers)

Most upvoted comments

Thanks @cescoffier . that works .

@mkouba : Is there a plan on adding this feature for exception type based method resolvers in the next 1,2 or 3 month roadmap for vertx-io web ?

@Route(path = "/*", type = FAILURE , exception = {XYZRuntimeException.class,IIegalArgumentException.class})
public void handleExceptionTypeX(RoutingContext context) {}
@Route(path = "/*", type = FAILURE , exception = {DEFRuntimeException.class})
public void handleExceptionTypeY(RoutingContext context) {}

if i am throwing one xyz runtime exception from down my chain why should it be wrapped as a CompositeException… can it not be simply thrown up the reactive chain as xyz runtimeException. ?

CompositeExceptions are only created if your first failure (the RuntimeException) triggers a second failure. So, you have at least 2 failures.

Another situation where CompositeException is used is when you combine multiple actions and explicitly require to collect all the failures. In this case, if there is more than one a CompositeException is used. Again, you have multiple failures.

Note that you should be able to retrieve the initial “main” failure using getCause().