Spring Webflux多个客户端超时

时间:2019-05-08 20:01:11

标签: spring spring-webflux reactor-netty

我有一个可以与其他几个服务交互的服务。因此,我为它们创建了单独的Web客户端(由于不同的基本路径)。我已经根据https://docs.spring.io/spring/docs/5.1.6.RELEASE/spring-framework-reference/web-reactive.html#webflux-client-builder-reactor-timeout分别为它们设置了超时时间,但这似乎没有有效。对于其中一项服务,尝试将ReadTimeout降低到2秒,但是该服务似乎没有超时(使用logging.level.org.springframework.web.reactive=debug的日志显示请求完成大约6-7秒)。

我使用的是spring5.1和netty 0.8,尽管我尚未完全使用webflux,但是我正在使用webclient进行阻止。我尝试对每个调用的超时进行处理,似乎有些调用确实响应了超时,而另一些则没有(更多详细信息以及下面的代码)

我如何初始化网络客户端-

@Bean
public WebClient serviceAWebClient(@Value("${serviceA.basepath}") String basePath,
                                          @Value("${serviceA.connection.timeout}") int connectionTimeout,
                                          @Value("${serviceA.read.timeout}") int readTimeout,
                                          @Value("${serviceA.write.timeout}") int writeTimeout) {

    return getWebClientWithTimeout(basePath, connectionTimeout, readTimeout, writeTimeout);
}

@Bean
public WebClient serviceBWebClient(@Value("${serviceB.basepath}") String basePath,
                                           @Value("${serviceB.connection.timeout}") int connectionTimeout,
                                           @Value("${serviceB.read.timeout}") int readTimeout,
                                           @Value("${serviceB.write.timeout}") int writeTimeout) {

    return getWebClientWithTimeout(basePath, connectionTimeout, readTimeout, writeTimeout);
}

@Bean
public WebClient serviceCWebClient(@Value("${serviceC.basepath}") String basePath,
                                           @Value("${serviceC.connection.timeout}") int connectionTimeout,
                                           @Value("${serviceC.read.timeout}") int readTimeout,
                                           @Value("${serviceC.write.timeout}") int writeTimeout) {

    return getWebClientWithTimeout(basePath, connectionTimeout, readTimeout, writeTimeout);
}

private WebClient getWebClientWithTimeout(String basePath,
                                          int connectionTimeout,
                                          int readTimeout,
                                          int writeTimeout) {


    TcpClient tcpClient = TcpClient.create()
            .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectionTimeout)
            .doOnConnected(connection ->
                    connection.addHandlerLast(new ReadTimeoutHandler(readTimeout))
                            .addHandlerLast(new WriteTimeoutHandler(writeTimeout)));

    return WebClient.builder().baseUrl(basePath)
            .clientConnector(new ReactorClientHttpConnector(HttpClient.from(tcpClient))).build();

我本质上如何使用它(每个Web客户端都有包装器类)-

Mono<ResponseA> serviceACallMono = ..;
Mono<ResponseB> serviceBCallMono = ..;
Mono.zip(serviceACallMono,serviceBCallMono,
(serviceAResponse, serviceBResponse) -> serviceC.getImportantData(serviceAResponse,serviceBResponse))
.flatMap(Function.identity)
.block();

因此,在上面,我注意到了以下内容-

如果降低serviceA ReadTimeout,则会收到超时错误。

如果降低serviceB ReadTimeout,则会收到超时错误。

如果我降低serviceC ReadTimeout,它不响应降低ReadTimeout。它只是一直工作直到得到响应。

那么,我在这里想念什么吗?我觉得这些超时应该在所有情况下都有效。请告诉我是否可以添加更多内容。

Edit:更新,因此我可以以一种更简单的方式重现该问题。 因此,对于-

return serviceACallMono
                .flatMap(notUsed -> serviceBCallMono);

serviceACallMono的超时很荣幸,但是无论您为serviceB降低多少,它都不会超时。

如果您只是取消订单-

return serviceBCallMono
                .flatMap(notUsed -> serviceACallMono);

现在可以接受serviceB的超时,但是不可以。

在观察此Edit行为的同时,我还更新了服务以返回Mono。

编辑2: 这本质上就是ServiceC#getImportantData中发生的事情-

@Override
    public Mono<ServiceCResponse> getImportantData(ServiceAResponse requestA,
                                                   ServiceBResponse requestB) {

        return serviceCWebClient.post()
                .uri(GET_IMPORTANT_DATA_PATH, requestB.getAccountId())
                .body(BodyInserters.fromObject(formRequest(requestA)))
                .retrieve()
                .bodyToMono(ServiceC.class);
    }

formRequest是一种简单的POJO转换方法。

1 个答案:

答案 0 :(得分:0)

我正在使用spring-boot入门级parent来拉动各种spring依赖项。从2.1.2版本升级到2.1.4版本似乎可以解决此问题。

相关问题