Search code examples
spring-webfluxreactive-programmingjava-17

Reactive streams java : How could I handle the error without interrupting request processing?


I wrote a small error handler. When an Exception appears, I do not interrupt the processing of the request, but only return false.

When there is no error, the flatmap method takes the value received from the call - service.existsByName(name) (true or false).


  
    public Mono<User> process(String name, User userDetails) {

        return service.existsByName(name)
                .doOnError(WebClientRequestException.class,
                        throwable -> {
                      
                            log.error("Failed to find...");
                        }
                )
                .onErrorResume(ex -> Mono.just(Boolean.FALSE))
                .flatMap(
                        isFound -> runUpdateColumn(userDetails,isFound)
                );
    }

public Mono<User> runUpdateColumn(userDetails,isFound){

if(isFound){
   service.updateColum(false);
   return Mono.just(userDetails);
}else{
  service.updateColum(true);
   return Mono.just(userDetails);
}

Of course, when I get true, the update of the required field goes in the normal order.

However, I lack the understanding that when false comes in a method downstream (flatMap), I would like to know that this value is received due to an error that occurred upstream (because if I get false, I also update the required field.).

Who has any ideas how to organize it?


Solution

  • You can "short" following operations by returning an empty publisher instead:

        public Mono<User> process(String name, User userDetails) {
            var potentiallyEmptyUser = service.existsByName(name)
                    .doOnError(WebClientRequestException.class, this::logError)
                    .onErrorResume(ex -> Mono.empty())
                    .flatMap(isFound -> runUpdateColumn(userDetails,isFound));
            return potentiallyEmptyUser;
        }
    

    Executing a flatMap over an empty publisher will produce a no-op, as no value is present to be transformed.

    Beware that the above strategy will propagate empty value, so consumers would receive an empty mono instead of a user. If you always want a default value, then you can use defaultIfEmpty or switchIfEmpty methods, to force a return value in case of error.

    For example, you could return input user as is :

    return potentiallyEmptyUser.defaultIfEmpty(userDetails);