Search code examples
javaspringreactive-programmingspring-webflux

Using block() on Mono<Foo> always fails


I have a function that works on a single element:

Mono<Foo> myFunction(String arg) {
  // do shiz
  return result;
}

Now, I am trying to reuse the above method to do the same, but for a list of args:

Mono<List<Foo>> myNewFunction(List<String> args) {
  Flux.fromIterable(args)
    .map(currentArg -> myFunction(currentArg))
    .map(Mono::block)
    .collectList();
}

But it always fails with the same error:

ava.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-3
...
Error has been observed at the following site(s):
    |_ checkpoint ⇢ Handler com.xxx.yyy.zzz.Controller#foo(InputRequest) [DispatcherHandler]
    |_ checkpoint ⇢ org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter [DefaultWebFilterChain]
    |_ checkpoint ⇢ HTTP POST "/v1/my/end/point" [ExceptionHandlingWebHandler]

(A controller is calling the myNewFunction)

I have verified that myFunction works when I call it directly from the controller. But when I go through myNewFunction, it fails.

How do I debug this and fix this? I can't tell what the error is. Thanks


Solution

  • First, Flux is an asynchronous sequence of 0-N items, while Mono end with 0-1 result, so your controller shoud return Flux<Foo>:

    Flux<Foo> myNewFunction(List<String> args) {
      return Flux.fromIterable(args)
        // if myFunction returns Mono, use flatMap instead of map.
        .flatMap(currentArg -> myFunction(currentArg));
    }
    

    If you want return Mono<List<Foo>> instead of Flux<Foo>, use collectList:

    Mono<List<Foo>> myNewFunction(List<String> args) {
      return Flux.fromIterable(args)
        .flatMap(currentArg -> myFunction(currentArg))
        .collectList();
    }
    

    Second, blocking operation should not used in non-blocking thread, which cause the error.