0

I have updated the Micronaut application from 2.5.XX to 3.0.0. As per the Micronaut documentation, the project reactor is the recommended reactive library to use for reactive programming.

@Controller("/product")
public class ProductController implements IProductOperation {
    @Override
    public Flux<List> freeTextSearch(String text) {
        return iProductManager.findFreeText(text).onErrorResume(throwable -> {
            return Flux.error(new GlobalException(throwable));
        });
    }
}

public interface IProductOperation {
    @Get(value = "/search/{text}")
    Flux<?> freeTextSearch(@NotBlank String text);
}

When I CURL the end point curl -X 'GET' 'http://localhost:8081/product/search/ffff' -H 'accept: application/json' it goes to the infinite.

Since I have an error on the system so return Flux.error(new GlobalException(throwable)); should return the 500 internal system error, however, it goes to the infinite

I have integrated rabbitMQ and rabbitMQ producer is shutdown. iProductManager.findFreeText(text) throws an exception since the rabbitMQ producer is not running. Instead of going infinite, it should throw an exception and global error handling should get called. But is is not working as expected

public class GlobalException extends RuntimeException{
    public GlobalException(Throwable throwable){super(throwable);}
}

This method never get called on error.

@Produces
@Singleton
@Requires(classes = {GlobalException.class, ExceptionHandler.class})
public class GlobalExceptionHandler implements ExceptionHandler<GlobalException, HttpResponse> {
    private static final Logger LOG = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    @Override
    public HttpResponse handle(HttpRequest request, GlobalException exception) {
        LOG.error(exception.getLocalizedMessage());
        LOG.error(exception.getCause().getMessage());
        Arrays.stream(exception.getStackTrace()).forEach(item -> LOG.error(item.toString()));
        return HttpResponse.serverError(exception.getLocalizedMessage());
    }
}

Logs

22:40:02.151 [default-nioEventLoopGroup-1-3] INFO  reactor.Flux.OnErrorResume.1 - onSubscribe(FluxOnErrorResume.ResumeSubscriber)
22:40:02.176 [default-nioEventLoopGroup-1-3] INFO  reactor.Flux.OnErrorResume.1 - request(1)
Svetlin Zarev
  • 14,713
  • 4
  • 53
  • 82
San Jaisy
  • 15,327
  • 34
  • 171
  • 290

1 Answers1

0

I think you're using the wrong reactor Flux operator:

  • onErrorResume switches to a different Flux in case of errors; you can consider that as a "fallback Flux". In your case, the fallback throws itself an error - this could explain the infinite loop.
  • onErrorMap should do what you're looking for: mapping an exception to another that can be used for the HTTP response

If you'd like to wrap all exceptions from that Flux, you could do:

return iProductManager.findFreeText(text)
        .onErrorMap(throwable -> new GlobalException(throwable));

Note that other onErrorMap methods allow you to have more fine-grained behavior.

Brian Clozel
  • 56,583
  • 15
  • 167
  • 176