我有一个可以与其他几个服务交互的服务。因此,我为它们创建了单独的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转换方法。
答案 0 :(得分:0)
我正在使用spring-boot入门级parent来拉动各种spring依赖项。从2.1.2版本升级到2.1.4版本似乎可以解决此问题。