jumping_monkey
jumping_monkey

Reputation: 7809

Spring Web Flux - WebClient - exchange - block - how to release the connection to the connection pool?

Current:

I am using spring-webflux-5.2.8.RELEASE and this is working "fine":

httpStatus = webClient
    .post()
    .uri(someUri)
    .headers(someHeaders)
    .bodyValue(someBody)
    .exchange()
    .map(ClientResponse::statusCode)
    .timeout(someTimeout)
    .doOnError(doSomething())
    .onErrorResume(ex -> Mono.empty())
    .block();

Issue:

When an error is returned, there is no issue, as the connection is destroyed and is not put back in the connection pool:

DEBUG r.n.resources.PooledConnectionProvider - [id: 0xa23f78ad, L:/127.0.0.1:7524 ! R:localhost/127.0.0.1:8443] Channel closed, now 0 active connections and 0 inactive connections

But when i get a successful response, the next post will fail/timeout:

java.util.concurrent.TimeoutException: Did not observe any item or terminal signal within 10000ms in 'map' (and no fallback has been configured)

As i needed to troubleshoot, I used a fix connection pool of only 1 connection like so:

@Bean
public WebClient.Builder webClientBuilder(){
    
    HttpClient httpClient = HttpClient.create(ConnectionProvider.create("pool", 1));
    
    return WebClient.builder()
        .clientConnector(new ReactorClientHttpConnector(httpClient));
}

I am guessing(i may be wrong as i am totally new to webclient and the reactive world) that the problem is that it is not releasing the connection after successfully getting the response and i think it is due to this.

When using a ClientResponse through the WebClient exchange() method, you have to make sure that the body is consumed or released...

What has been tried:

I tried to do a releaseBody() like so(but that does not work as the next post is still failing):

.map(clientResponse -> { 
    HttpStatus statusCode = clientResponse.statusCode();
    clientResponse.releaseBody();
    return statusCode;
})

P.S I need to use the block(). That can't be changed as i need the response to move on, and i just need to get the status code. I am using WebClient, because i read somewhere that rest template is going to be deprecated in favor of ... WebClient. I hope someone can help.

Update 1:

I enabled metrics and indeed the connection is not released:

reactor_netty_connection_provider_fixedPool_total_connections{id="1591603494",remote_address="localhost:8443",} 1.0 reactor_netty_connection_provider_fixedPool_active_connections{id="1591603494",remote_address="localhost:8443",} 1.0

Update 2

Found this: https://github.com/spring-projects/spring-framework/issues/20474!

Update 3

I tried with the default number of connections(i.e 500) and i can notice that the number of active connections keep increasing after each post i do :-(

[reactor-http-nio-2] DEBUG r.n.resources.PooledConnectionProvider - [id: 0x2316e048, L:/127.0.0.1:32787 - R:localhost/127.0.0.1:8443] Channel connected, now 7 active connections and 0 inactive connections

Upvotes: 3

Views: 7306

Answers (1)

jumping_monkey
jumping_monkey

Reputation: 7809

This is what is working for me:

HttpStatus httpStatus = null;
Mono<HttpStatus> monoHttpStatus  = null;
:           
WebClient webClient = xxx.getWebClient();
:       
try {
    monoHttpStatus  = webClient
        .post()
        .uri(someUri)
        .headers(someHeaders)
        .bodyValue(someBody)
        .exchange()
        .map(clientResponse -> 
            clientResponse.releaseBody().thenReturn(clientResponse.statusCode()))
        .timeout(someTimeout)
        .doOnError(Exception.class, e -> logger.error("An exception has occurred: ", e))
        .onErrorResume(ex -> Mono.empty())
        .block();
                
        if(monoHttpStatus != null)
            httpStatus = monoHttpStatus.block();            
}
:

//SomeOtherClass
@Autowired
private WebClient.Builder webClientBuilder;
public WebClient getWebClient() {
        
    :
    
    webClient= webClientBuilder.baseUrl(baseUrl)
                   .build();
    :   
    return webClient;
}

And i am now seeing this after the post is done:

DEBUG reactor.util.Loggers$Slf4JLogger.debug[249] [reactor-http-nio-1] [id: 0x6b0568a3, L:/127.0.0.1:10168 - R:localhost/127.0.0.1:8443] Releasing channel
DEBUG reactor.util.Loggers$Slf4JLogger.debug[254] [reactor-http-nio-1] [id: 0x6b0568a3, L:/127.0.0.1:10168 - R:localhost/127.0.0.1:8443] Channel cleaned, now 0 active connections and 1 inactive connections

Upvotes: 1

Related Questions