Issue
I have written code that uses webclient to call another endpoint and want to add reactive error handling. However, it seems my understanding of doOnError or onErrorResume may not be correct:
webClient
.get()
.uri(someUri)
.retrieve()
.bodyToFlux(Some.class)
.onErrorResume(throwable -> {
log.error("Error occurred when calling other service: {}", throwable.getMessage());
return Flux.error(new RunTimeException("Exception type: " + throwable.getClass() + " Exception message: " + throwable.getMessage()));
});
Then intention is that this call is actually part of a larger reactive chain that calls this, and if an exception is thrown whilst running the api call (.get().retrieve()
), onErrorResume
should throw and pass on the exception to the higher level reactive chain caller.
I tried to unit test the validity of this by:
Mockito.when(webClient.get().uri(URI.create(uri)).retrieve()).thenThrow(new RuntimeException("Hello world exception thrown"));
But noticed that the exception just gets thrown, and the code terminates at the .retrieve step of the reactive chain, rather than proceeding to the onErrorResume
step.
Solution
This is because your test throws an error when constructing the retrieve
Mono, instead of returning a functional Mono that immediately emits an error when subscribed to. Thus it's not your data flow that is in error, but the pipeline handling the data flow itself.
You can solve this by returning a Mono.error
:
Mockito.when(webClient.get().uri(URI.create(uri)).retrieve())
.thenReturn(Mono.error(new RuntimeException("Hello world exception thrown")));
Answered By - Patrick Hooijer
Answer Checked By - Mildred Charles (JavaFixing Admin)