vertx-web icon indicating copy to clipboard operation
vertx-web copied to clipboard

Inconsistent exception handling

Open HuiiBuh opened this issue 4 years ago • 4 comments

Version

Vertx Version 4.0.2

Context

I have a problem with the exception handling vertx . makesEvery time I use the evetbus to connect to another verticle the exception does not get handled the way I expect it to get handled.

My goal is for example to write a errorHandler(500) which prints i want this to be displayed every time an uncaught exception happens. And if I try curl "http://localhost:8888/works this woks. The exception gets caught and errorHandler returns i want this to be displayed.
But if I communicate with another verticle with the eventbus the exception does not get caught and transfered to the errorHandler. This results in a pending request and with enough patience in a timeout, because the request did not get answered (In this calse curl http://localhost:8888/does-not-work)

Interestingly the error gets caught by vertx.exceptionHandler, but not by the errorHandler.

final Router router = Router.router(vertx);
final EventBus eventBus = vertx.eventBus();

router.get("/works").handler(routingContext -> {
  throw new RuntimeException("gets caught");
});

router.get("/does-not-work").handler(routingContext -> {
  eventBus.request("image", null, asyncResponse -> {
    throw new RuntimeException("does not work");
  });
});

router.errorHandler(500, routingContext -> {
  routingContext.end("i want this to be displayed");
});

vertx.exceptionHandler(e -> {
  System.err.println(e.toString());
  // Prints: java.lang.RuntimeException: does not work
});

Expectation

I would expect vertx to handle Exceptions which happen in a callback form the evetbus the same way vertx handles exceptions which happen without a callback.
Perhaps this is a lack of understanding, but it seems weird and inconsistent.

Extra

OS: Centos 7.9 openjdk version: "1.8.0_275"

HuiiBuh avatar Feb 18 '21 16:02 HuiiBuh

Related: ~~I was looking into having a generic handler for dealing with "Record Not Found" exceptions. In order to avoid repetition, my services would only throw a RecordNotFoundException and then a centralized error handler would pick it up and format it consistently. But in the error handler the failure() method only returns ServiceException without its cause being available.~~

Update: I found that if I derive my exception from ServiceException, it becomes available in the handler.

milgner avatar Mar 02 '21 09:03 milgner

Version

Vertx Version 4.0.2

Context

I have a problem with the exception handling vertx . makesEvery time I use the evetbus to connect to another verticle the exception does not get handled the way I expect it to get handled.

My goal is for example to write a errorHandler(500) which prints i want this to be displayed every time an uncaught exception happens. And if I try curl "http://localhost:8888/works this woks. The exception gets caught and errorHandler returns i want this to be displayed. But if I communicate with another verticle with the eventbus the exception does not get caught and transfered to the errorHandler. This results in a pending request and with enough patience in a timeout, because the request did not get answered (In this calse curl http://localhost:8888/does-not-work)

Interestingly the error gets caught by vertx.exceptionHandler, but not by the errorHandler.

final Router router = Router.router(vertx);
final EventBus eventBus = vertx.eventBus();

router.get("/works").handler(routingContext -> {
  throw new RuntimeException("gets caught");
});

router.get("/does-not-work").handler(routingContext -> {
  eventBus.request("image", null, asyncResponse -> {
    throw new RuntimeException("does not work");
  });
});

router.errorHandler(500, routingContext -> {
  routingContext.end("i want this to be displayed");
});

vertx.exceptionHandler(e -> {
  System.err.println(e.toString());
  // Prints: java.lang.RuntimeException: does not work
});

Expectation

I would expect vertx to handle Exceptions which happen in a callback form the evetbus the same way vertx handles exceptions which happen without a callback. Perhaps this is a lack of understanding, but it seems weird and inconsistent.

Extra

OS: Centos 7.9 openjdk version: "1.8.0_275"

I am also having similar issue, where I couldn't send error to front-end/client, instead waiting for timeout to occur and sending timeout exception. I would be good if this can be addressed.

pskarthic avatar Mar 13 '21 06:03 pskarthic

There's a scope problem with the example code:

...
router.get("/does-not-work").handler(routingContext -> {
  eventBus.request("image", null, asyncResponse -> {
    // This code is defined inside a lambda, which means the execution is not specifically bound to
    // the current vertx-web route, in this case it is bound to the execution of the eventbus (which
    // means vertx-core.
    throw new RuntimeException("does not work");
    // because it's not bound to the route, exceptions here are not catched by the router
    // but by core, that is why the vertx.exceptionHandler() can catch it
  });
});

Maybe an alternative to solve this is to rewrite the code as:

router.get("/does-not-work").handler(routingContext -> {
  eventBus.request("image", null, asyncResponse -> {
    try {
      throw new RuntimeException("does not work");
    } catch (RuntimeException e) {
     routingContext.fail(500, e);
    }
  });
});

This way exceptions on user code are handled by the user as the user so wants. Also note that the same should be done for the eventbus to be totally complete:

router.get("/does-not-work").handler(routingContext -> {
  eventBus.request("image", null, asyncResponse -> {
    if (asyncResponse.failed()) {
      routingContext.fail(500, asyncResponse.cause());
      return;
    }
    try {
      throw new RuntimeException("does not work");
    } catch (RuntimeException e) {
     routingContext.fail(500, e);
    }
  });
});

pmlopes avatar Apr 16 '21 08:04 pmlopes

Thanks for your reply. That is the solution I am currentely using. It is just not very elegant to surround everything with a try catch block

HuiiBuh avatar Apr 27 '21 07:04 HuiiBuh