Can I use block() method of Flux returned from Spring5's WebClient?

前端 未结 1 843
遇见更好的自我
遇见更好的自我 2021-01-12 10:09

I created Spring Boot 2.0 demo application which contains two applications that communicate using WebClient. And I\'m suffering that they often stop communicating when I use

1条回答
  •  礼貌的吻别
    2021-01-12 10:39

    First, let me point that using Flux.fromIterable(items) is advised only if items has been fetched from memory, no I/O involved. Otherwise chances are you'd be using a blocking API to get it - and this can break your reactive application. In this case, this is an in-memory list, so no problem. Note that you can also go Flux.just(item1, item2, item3).

    Using the following is the most efficient:

    @GetMapping("/")
    public Flux findFlux() {
      return webClient.get()
        .retrieve()
        .bodyToFlux(Item.class);
    }
    

    Item instances will be read/written, decoded/encoded on the fly in a very efficient way.

    On the other hand, this is not the preferred way:

    @GetMapping("/block")
    public List findBlock() {
      return webClient.get()
        .retrieve()
        .bodyToFlux(Item.class)
        .collectList()
        .block(Duration.ofSeconds(10L));
    }
    

    In this case, your front application is buffering in memory the whole items list with collectList but is also blocking one of the few server threads available. This might cause very poor performance because your server might be blocked waiting for that data and can't service other requests at the same time.

    In this particular case it's worse, since the application totally breaks. Looking at the console, we can see the following:

    WARN 3075 --- [ctor-http-nio-7] io.netty.util.concurrent.DefaultPromise  : An exception was thrown by reactor.ipc.netty.channel.PooledClientContextHandler$$Lambda$532/356589024.operationComplete()
    
    reactor.core.Exceptions$BubblingException: java.lang.IllegalArgumentException: Channel [id: 0xab15f050, L:/127.0.0.1:59350 - R:localhost/127.0.0.1:8081] was not acquired from this ChannelPool
        at reactor.core.Exceptions.bubble(Exceptions.java:154) ~[reactor-core-3.1.3.RELEASE.jar:3.1.3.RELEASE]
    

    This is probably linked to a reactor-netty client connection pool issue that should be fixed in 0.7.4.RELEASE. I don't know the specifics of this, but I suspect the whole connection pool gets corrupted as HTTP responses aren't properly read from the client connections.

    Adding spring-boot-starter-web does make your application use Tomcat, but it mainly turns your Spring WebFlux application into a Spring MVC application (which now supports some reactive return types, but has a different runtime model). If you wish to test your application with Tomcat, you can add spring-boot-starter-tomcat to your POM and this will use Tomcat with Spring WebFlux.

    0 讨论(0)
提交回复
热议问题