Uploaded image for project: 'Spring Framework'
  1. Spring Framework
  2. SPR-15920

Ensure that WebClient disposes the HTTP client connection once the client response is consumed

    Details

    • Type: Improvement
    • Status: Closed
    • Priority: Critical
    • Resolution: Complete
    • Affects Version/s: None
    • Fix Version/s: 5.0 RC4
    • Component/s: Reactive, Web:Client
    • Labels:
      None
    • Last commented by a User:
      false

      Description

      Problems with the WebClient API

      Given the current WebClient API, it is possible to have:

      Mono<String> result = this.webClient.get()
      				.uri("/greeting")
      				.retrieve()
      				.bodyToMono(String.class);
      

      In that case, we're consuming the response body completely; under the covers, reactor-netty will dispose the connection (close it or return it to the connection pool) as soon as the body has been consumed.

      But we can also do this:

      Mono<HttpStatus> status = this.webClient.get()
      				.uri("/example")
      				.exchange()
      				.map(response -> response.statusCode());
      

      In that case, the body is not consumed, and the underlying client has no way of knowing that the connection should be closed. This can lead to issues with the connection pool, memory leaks, etc.

      In the ClientConnector#connect method, before returning the `ClientHttpResponse`, we could do something like:

      responseMono.doOnTerminate((response, ex) -> {
        if (response != null) {
          response.dispose();
        }
      })
      

      But unfortunately, this will close the connection too soon. The first example can be rewritten like:

      Mono<ResponseEntity<String>> result = this.webClient.get()
      				.uri("/greeting")
      				.exchange()
      				.flatMap(response -> response.toEntity(String.class));
      

      With the flatMap operator, we wait until the Mono<ClientHttpResponse> is completed and proceed with the body. The completion triggers that doOnTerminate operator.

      Reactor Netty changes

      Reactor Netty is currently dealing with this in its API and considering the following changes:

      public interface ResponseReceiver  {
       
        // HttpClientResponse has no reference to the body, just headers/status/etc
        Mono<HttpClientResponse> response();
      
        <V> Flux<V> response(BiFunction<? super HttpClientResponse, ? super ByteBufFlux, ? extends Publisher<? extends V>> receiver);
      
        ByteBufFlux responseContent();
      
        <V> Mono<V> responseSingle(BiFunction<? super HttpClientResponse, ? super ByteBufMono, ? extends Mono<? extends V>> receiver);
      
      }
      

      With this type of changes, the response body Publisher is tied back to the lifecycle of the connection.

      We need to revisit our current client API to make sure that the connection lifecycle can be properly managed for the underlying client library.

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                bclozel Brian Clozel
                Reporter:
                bclozel Brian Clozel
                Last updater:
                Rossen Stoyanchev
              • Votes:
                0 Vote for this issue
                Watchers:
                2 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved:
                  Days since last comment:
                  49 weeks, 1 day ago