How could we use @ExceptionHandler with spring web flux?

Evgen picture Evgen · Mar 6, 2018 · Viewed 15.9k times · Source

In spring web we could use annotation @ExceptionHandler for handling server and client errors for controllers.

I've tried to use this annotation with web-flux controller and it still worked for me, but after some investigation I've found out here

The situation with Spring Web Reactive is more complicated. Because the reactive streams are evaluted by a different thread than the one that executes the controllers method, the exceptions won’t be propagated to the controller thread automatically. This means that the @ExceptionHandler method will work only for exceptions that are thrown in the thread that handles the request directly. Exceptions thrown in the stream will have to be propagated back to the thread if we want to use the @ExceptionHandler feature. This seems like a bit of a let down but at the time of writing this Spring 5 is still not released so error handling might still get better.

So my question is how to propagate back exception to the thread. Is there a good example or article about using @ExceptionHandler and Spring web flux?

Updated: From spring.io it looks like it's supported, but still lack general understanding

Thanks,

Answer

Brian Clozel picture Brian Clozel · Mar 6, 2018

You can use @ExceptionHandler annotated methods to handle errors that happen within the execution of a WebFlux handler (e.g., your controller method). With MVC you can indeed also handle errors happening during the mapping phase, but this is not the case with WebFlux.

Back to your exception propagation question, the article you're sharing is not accurate.

In reactive applications, the request processing can indeed hop from one thread to another at any time, so you can't rely on the "one thread per request" model anymore (think: ThreadLocal).

You don't have to think about exception propagation or how threads are managed, really. For example, the following samples should be equivalent:

@GetMapping("/test")
public Mono<User> showUser() {
  throw new IllegalStateException("error message!);
}


@GetMapping("/test")
public Mono<User> showUser() {
  return Mono.error(new IllegalStateException("error message!));
}

Reactor will send those Exceptions as error signals as expected in the Reactive Streams contract (see the "error handling" documentation section for more on that).