spring-webfluxproject-reactorspring-webclientreactor-netty

Reactor Netty Http responseTimeout doesn't override other timeouts if value is greater


I'm trying to change the responseTimeout on the WebClient for some requests. However, the responseTimeout only overrides readTimeout if the value is less than the ReadTimeout configuration on the HttpClient. Is this expected? Should a readTimeout even be set?

For example, the 15 seconds set on the reactorRequest will not override the readTimeout configuration.

val httpClient = HttpClient.create()
            .doOnConnected {
                it.addHandlerFirst(ReadTimeoutHandler(10)
                it.addHandlerFirst(WriteTimeoutHandler(10)
            }
            .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, httpConnectionConfig.connectTimeout.toInt())


val outgoingRequest = webClient.method(incomingRequest.method)
            .uri(forwardUriTransform.uri)
            .headers {
                it.addAll(getForwardedHeaders(incomingRequest))
            }
            .body(incomingRequest.body, DataBuffer::class.java)
            .attribute(API_CONFIG_ATTR_KEY, forwardConfig)
            .httpRequest { httpRequest: ClientHttpRequest ->
                val reactorRequest: HttpClientRequest = httpRequest.getNativeRequest()
                reactorRequest.responseTimeout(Duration.ofSeconds(15))
            }

Solution

  • I would say what you observe is expected - you add by yourself ReadTimeoutHandler with 10s and then you have responseTimeout - 15s (responseTimeout is again read timeout as you expect to read the response within the specified time).

    Reactor Netty does not know what kind of custom ChannelHandlers are added to the pipeline, why they are added etc. All custom ChannelHandlers are responsibility for the developer that decided to add them to the pipeline.

    That said, if you want to achieve global (default) responseTimeout and also such per request, the sample above has to be changed to use Reactor Netty API for global (default) responseTimeout:

    val httpClient = HttpClient.create()
            .doOnConnected {
                //it.addHandlerFirst(ReadTimeoutHandler(10)
                it.addHandlerFirst(WriteTimeoutHandler(10)
            }
            .responseTimeout(Duration.ofSeconds(10))
            .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, httpConnectionConfig.connectTimeout.toInt())
    
    
    val outgoingRequest = webClient.method(incomingRequest.method)
            .uri(forwardUriTransform.uri)
            .headers {
                it.addAll(getForwardedHeaders(incomingRequest))
            }
            .body(incomingRequest.body, DataBuffer::class.java)
            .attribute(API_CONFIG_ATTR_KEY, forwardConfig)
            .httpRequest { httpRequest: ClientHttpRequest ->
                val reactorRequest: HttpClientRequest = httpRequest.getNativeRequest()
                reactorRequest.responseTimeout(Duration.ofSeconds(15))
            }
    

    More about responseTimeout can be found here and here