0Day Forums
How to set a timeout in Spring 5 WebFlux WebClient - Printable Version

+- 0Day Forums (https://zeroday.vip)
+-- Forum: Coding (https://zeroday.vip/Forum-Coding)
+--- Forum: FrameWork (https://zeroday.vip/Forum-FrameWork)
+---- Forum: Spring (https://zeroday.vip/Forum-Spring)
+---- Thread: How to set a timeout in Spring 5 WebFlux WebClient (/Thread-How-to-set-a-timeout-in-Spring-5-WebFlux-WebClient)

Pages: 1 2


How to set a timeout in Spring 5 WebFlux WebClient - tulipgfsjqjhq - 08-02-2023

I'm trying to set timeout on my WebClient, here is the current code :

SslContext sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();

ClientHttpConnector httpConnector = new ReactorClientHttpConnector(opt -> {
opt.sslContext(sslContext);
HttpClientOptions option = HttpClientOptions.builder().build();
opt.from(option);
});
return WebClient.builder().clientConnector(httpConnector).defaultHeader("Authorization", xxxx)
.baseUrl(this.opusConfig.getBaseURL()).build();


I need to add timeout and also pooling strategy, I was thinking of something like that :

PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(this.applicationConfig.getHttpClientMaxPoolSize());
cm.setDefaultMaxPerRoute(this.applicationConfig.getHttpClientMaxPoolSize());
cm.closeIdleConnections(this.applicationConfig.getServerIdleTimeout(), TimeUnit.MILLISECONDS);

RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(this.applicationConfig.getHttpClientSocketTimeout())
.setConnectTimeout(this.applicationConfig.getHttpClientConnectTimeout())
.setConnectionRequestTimeout(this.applicationConfig.getHttpClientRequestTimeout()).build();

CloseableHttpClient httpClient = HttpClients.custom().setDefaultRequestConfig(requestConfig).setConnectionManager(cm).build();

But I can't figure out how to set the httpClient in my webclient




RE: How to set a timeout in Spring 5 WebFlux WebClient - warlordism178176 - 08-02-2023

Here's how I did it (thanks to @Artem)

SslContext sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();

ClientHttpConnector httpConnector = new ReactorClientHttpConnector(options -> {
options.sslContext(sslContext);
options.option(ChannelOption.SO_TIMEOUT, this.applicationConfig.getHttpClientRequestTimeout());
options.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, this.applicationConfig.getHttpClientConnectTimeout());
options.poolResources(PoolResources.fixed("myPool", this.applicationConfig.getHttpClientMaxPoolSize()));
});

return WebClient.builder().clientConnector(httpConnector).defaultHeader("Authorization", "xxxx")
.baseUrl(this.config.getBaseURL()).build();




RE: How to set a timeout in Spring 5 WebFlux WebClient - perleioo - 08-02-2023

To set the read and connect timeout I use the method below, because the SO_TIMEOUT option is not available for channels using NIO (and giving the warning `Unknown channel option 'SO_TIMEOUT' for channel '[id: 0xa716fcb2]'`)

ReactorClientHttpConnector connector = new ReactorClientHttpConnector(
options -> options.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 2000)
.compression(true)
.afterNettyContextInit(ctx -> {
ctx.addHandlerLast(new ReadTimeoutHandler(5000, TimeUnit.MILLISECONDS));
}));
return WebClient.builder()
.clientConnector(connector)
.build();



RE: How to set a timeout in Spring 5 WebFlux WebClient - tournament923620 - 08-02-2023

The WebFlux `WebClient` doesn't use Apache Commons HTTP Client. Although you might be able to implement one solution via custom `ClientHttpConnector`. The existing `ReactorClientHttpConnector` is based on the Netty. So, consider to use Netty options to configure the client, e.g.:

ReactorClientHttpConnector connector =
new ReactorClientHttpConnector(options ->
options.option(ChannelOption.SO_TIMEOUT, this.applicationConfig.getHttpClientConnectTimeout()));

or

.onChannelInit(channel -> channel.config().setConnectTimeoutMillis(this.applicationConfig.getHttpClientConnectTimeout()))

**UPDATE**

We also can use `ReadTimeoutHandler`:

.onChannelInit(channel ->
channel.pipeline()
.addLast(new ReadTimeoutHandler(this.applicationConfig.getHttpClientConnectTimeout())))



RE: How to set a timeout in Spring 5 WebFlux WebClient - lastditch584 - 08-02-2023

Based on the above comment if you want to add a Socket Timeout just add it as another option in the same timeoutClient.

TcpClient timeoutClient = TcpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, SECONDS*10) //Connect Timeout
.option(ChannelOption.SO_TIMEOUT,1000) // Socket Timeout
.doOnConnected(
c -> c.addHandlerLast(new ReadTimeoutHandler(SECONDS))
.addHandlerLast(new WriteTimeoutHandler(SECONDS)));
return webClientBuilder.baseUrl(YOUR_URL)
.clientConnector(new ReactorClientHttpConnector(HttpClient.from(timeoutClient)))
.build();


RE: How to set a timeout in Spring 5 WebFlux WebClient - concentivenojnxwhebo - 08-02-2023

With Spring Webflux 5.1.8 I ran into problems yielding the error messages below using the answer from [mcoolive][1] when executing multiple subsequent tests that uses the `WebClient`.<br/>

> Force-closing a channel whose registration task was not accepted by an
> event loop <br/>
> Failed to submit a listener notification task. Event loop shut down?

Adding a connection provider and loop resources solved my problem:
```java
final ConnectionProvider theTcpClientPool = ConnectionProvider.elastic("tcp-client-pool");
final LoopResources theTcpClientLoopResources = LoopResources.create("tcp-client-loop");

final TcpClient theTcpClient = TcpClient
.create(theTcpClientPool)
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
.runOn(theTcpClientLoopResources)
.doOnConnected(theConnection -> {
theConnection.addHandlerLast(new ReadTimeoutHandler(mTimeoutInMillisec, TimeUnit.MILLISECONDS));
theConnection.addHandlerLast(new WriteTimeoutHandler(mTimeoutInMillisec, TimeUnit.MILLISECONDS));
});

WebClient theWebClient = WebClient.builder()
.baseUrl(mVfwsServerBaseUrl)
.clientConnector(new ReactorClientHttpConnector(HttpClient.from(theTcpClient)))
.build();
```


[1]:

[To see links please register here]




RE: How to set a timeout in Spring 5 WebFlux WebClient - pramszfoxagxl - 08-02-2023

Rather than creating your own `WebClient.Builder`, you can provide a custom `ReactorNettyHttpClientMapper` which is going to be applied to the default `WebClient.Builder`:

```kotlin
@Configuration
class MyAppConfiguration {

@Bean
fun reactorNettyHttpClientMapper(): ReactorNettyHttpClientMapper {
return ReactorNettyHttpClientMapper { httpClient ->
httpClient.tcpConfiguration { tcpClient ->
tcpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 30_000)
.doOnConnected { connection ->
connection.addHandlerLast(ReadTimeoutHandler(60))
.addHandlerLast(WriteTimeoutHandler(60))
}
}
}
}
}
```


RE: How to set a timeout in Spring 5 WebFlux WebClient - Sirstonecrop284 - 08-02-2023

As Spring Webflux was updated, here is a solution that works for Java (based on the [answer][1] for Kotlin):

TcpClient timeoutClient = TcpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, SECONDS*1000)
.doOnConnected(
c -> c.addHandlerLast(new ReadTimeoutHandler(SECONDS))
.addHandlerLast(new WriteTimeoutHandler(SECONDS)));
return webClientBuilder.baseUrl(YOUR_URL)
.clientConnector(new ReactorClientHttpConnector(HttpClient.from(timeoutClient)))
.build();


**UPDATE 2021**

since `HttpClient.from(TcpClient)` is deprectaed now it's even easier:

```java
return WebClient.builder()
.baseUrl(YOUR_URL)
.clientConnector(new ReactorClientHttpConnector(HttpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, SECONDS * 1000)
.doOnConnected(c -> c.addHandlerLast(new ReadTimeoutHandler(SECONDS))
.addHandlerLast(new WriteTimeoutHandler(SECONDS)))))
.build();
```

[1]:

[To see links please register here]




RE: How to set a timeout in Spring 5 WebFlux WebClient - brightman117 - 08-02-2023

You can use overloaded block() method which accepts a timeout on Mono object.
Or there is a timeout() method directly available on Mono object.

WebClient webClient = WebClient.builder()
.baseUrl( "https://test.com" )
.defaultHeader( HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE )
.build();

webClient.post()
.uri( "/services/some/uri" )
.body( Mono.just( YourEntityClassObject ), YourEntityClass.class )
.retrieve()
.bodyToMono( String.class )
.timeout(Duration.ofMillis( 5000 )) // option 1
.block(Duration.ofMillis( 5000 )); // option 2


RE: How to set a timeout in Spring 5 WebFlux WebClient - blondiearino - 08-02-2023

ReactorClientHttpConnector API changed in version [Spring WebFlux 5.1][1].

So I do the following (Kotlin syntax, based on @joshiste example):

val tcpClient = TcpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10_000)
.doOnConnected { connection ->
connection.addHandlerLast(ReadTimeoutHandler(10))
.addHandlerLast(WriteTimeoutHandler(10))
}

val myWebClient = webClientBuilder
.clientConnector(ReactorClientHttpConnector(HttpClient.from(tcpClient)))
.baseUrl(myEndPoint)
.build()

UPDATE 2021

HttpClient.from in deprecated in last version of Reactive Netty. It was copying the configuration of the tcpClient. Now we can configure httpClient directly.

val httpClient = HttpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 10_000)
.doOnConnected { connection ->
connection.addHandlerLast(ReadTimeoutHandler(10))
.addHandlerLast(WriteTimeoutHandler(10))
}

val myWebClient = webClientBuilder
.clientConnector(ReactorClientHttpConnector(httpClient))
.baseUrl(myEndPoint)
.build()


[1]:

[To see links please register here]

-