Java Spring Boot REST API - 请求超时?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/34852236/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Spring Boot REST API - request timeout?
提问by Jesper Lehtinen
I have a Spring Boot REST service that sometimes call third party services as a part of a request. I would like to set a timeout on all my resources (let's say 5 seconds), so that if any request handling (the whole chain, from incoming to response) takes longer than 5 seconds my controllers responds with HTTP 503 instead of the actual response. It would be awesome if this was just a Spring property, for example setting
我有一个 Spring Boot REST 服务,它有时会在请求中调用第三方服务。我想为我的所有资源设置一个超时时间(假设为 5 秒),以便如果任何请求处理(整个链,从传入到响应)花费的时间超过 5 秒,我的控制器将使用 HTTP 503 而不是实际响应进行响应. 如果这只是一个 Spring 属性,例如设置,那就太棒了
spring.mvc.async.request-timeout=5000
but I haven't had any luck with that. I've also tried extending WebMvcConfigurationSupport and overriding configureAsyncSupport:
但我对此没有任何运气。我还尝试扩展 WebMvcConfigurationSupport 并覆盖 configureAsyncSupport:
@Override
public void configureAsyncSupport(final AsyncSupportConfigurer configurer) {
configurer.setDefaultTimeout(5000);
configurer.registerCallableInterceptors(timeoutInterceptor());
}
@Bean
public TimeoutCallableProcessingInterceptor timeoutInterceptor() {
return new TimeoutCallableProcessingInterceptor();
}
without any luck.
没有任何运气。
I suspect I have to manually time all my third party calls, and if they take too long, throw a timeout exception. Is that right? Or is there any easier, holistic solution that covers all my request endpoints?
我怀疑我必须手动为所有第三方调用计时,如果它们花费的时间太长,则抛出超时异常。那正确吗?或者是否有任何更简单的整体解决方案涵盖我的所有请求端点?
采纳答案by Cyril
You need to return a Callable<>
if you want spring.mvc.async.request-timeout=5000
to work.
Callable<>
如果你想spring.mvc.async.request-timeout=5000
工作,你需要返回一个。
@RequestMapping(method = RequestMethod.GET)
public Callable<String> getFoobar() throws InterruptedException {
return new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(8000); //this will cause a timeout
return "foobar";
}
};
}
回答by Pankaj Pandey
if you are using RestTemplate than you should use following code to implement timeouts
如果您使用的是 RestTemplate,则应该使用以下代码来实现超时
@Bean
public RestTemplate restTemplate() {
return new RestTemplate(clientHttpRequestFactory());
}
private ClientHttpRequestFactory clientHttpRequestFactory() {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setReadTimeout(2000);
factory.setConnectTimeout(2000);
return factory;
}}
The xml configuration
xml配置
<bean class="org.springframework.web.client.RestTemplate">
<constructor-arg>
<bean class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory"
p:readTimeout="2000"
p:connectTimeout="2000" />
</constructor-arg>
回答by demaniak
I would suggest you have a look at the Spring Cloud Netflix Hystrix starter to handle potentially unreliable/slow remote calls. It implements the Circuit Breaker pattern, that is intended for precisely this sorta thing.
我建议您查看 Spring Cloud Netflix Hystrix starter 以处理可能不可靠/缓慢的远程调用。它实现了断路器模式,正是为了这种事情。
回答by Danylo Zatorsky
You can try server.connection-timeout=5000
in your application.properties. From the official documentation:
您可以server.connection-timeout=5000
在 application.properties 中尝试。从官方文档:
server.connection-timeout= # Time in milliseconds that connectors will wait for another HTTP request before closing the connection. When not set, the connector's container-specific default will be used. Use a value of -1 to indicate no (i.e. infinite) timeout.
server.connection-timeout= # 连接器在关闭连接之前等待另一个 HTTP 请求的时间(以毫秒为单位)。如果未设置,将使用连接器特定于容器的默认值。使用值 -1 表示没有(即无限)超时。
On the other hand, you may want to handle timeouts on the client side using Circuit Breaker pattern as I have already described in my answer here: https://stackoverflow.com/a/44484579/2328781
另一方面,您可能希望使用断路器模式在客户端处理超时,正如我在此处的回答中所述:https: //stackoverflow.com/a/44484579/2328781
回答by fvorraa
The @Transactional annotation takes a timeout parameter where you can specify timeout in seconds for a specific method in the @RestController
@Transactional 注释采用超时参数,您可以在其中指定 @RestController 中特定方法的超时时间(以秒为单位)
@RequestMapping(value = "/method",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
@Timed
@Transactional(timeout = 120)
回答by MiguelMunoz
In Spring properties files, you can't just specify a number for this property. You also need to specify a unit. So you can say spring.mvc.async.request-timeout=5000ms
or spring.mvc.async.request-timeout=5s
, both of which will give you a 5-second timeout.
在 Spring 属性文件中,您不能只为此属性指定一个数字。您还需要指定一个单位。所以你可以说spring.mvc.async.request-timeout=5000ms
or spring.mvc.async.request-timeout=5s
,这两者都会给你一个 5 秒的超时时间。
回答by geliba187
I feel like none of the answers really solve the issue. I think you need to tell the embedded server of Spring Boot what should be the maximum time to process a request. How exactly we do that is dependent on the type of the embedded server used.
我觉得没有一个答案能真正解决问题。我认为您需要告诉 Spring Boot 的嵌入式服务器处理请求的最长时间应该是多少。我们究竟如何做到这一点取决于所使用的嵌入式服务器的类型。
In case of Undertow, one can do this:
在 Undertow 的情况下,可以这样做:
@Component
class WebServerCustomizer : WebServerFactoryCustomizer<UndertowServletWebServerFactory> {
override fun customize(factory: UndertowServletWebServerFactory) {
factory.addBuilderCustomizers(UndertowBuilderCustomizer {
it.setSocketOption(Options.READ_TIMEOUT, 5000)
it.setSocketOption(Options.WRITE_TIMEOUT, 25000)
})
}
}
Spring Boot official doc: https://docs.spring.io/spring-boot/docs/2.2.0.RELEASE/reference/html/howto.html#howto-configure-webserver
Spring Boot 官方文档:https: //docs.spring.io/spring-boot/docs/2.2.0.RELEASE/reference/html/howto.html#howto-configure-webserver
回答by Komoo
You can configure the Async thread executor for your Springboot REST services. The setKeepAliveSeconds() should consider the execution time for the requests chain. Set the ThreadPoolExecutor's keep-alive seconds. Default is 60. This setting can be modified at runtime, for example through JMX.
您可以为 Springboot REST 服务配置异步线程执行器。setKeepAliveSeconds() 应该考虑请求链的执行时间。设置 ThreadPoolExecutor 的保持活动秒数。默认值为 60。可以在运行时修改此设置,例如通过 JMX。
@Bean(name="asyncExec")
public Executor asyncExecutor()
{
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(3);
executor.setMaxPoolSize(3);
executor.setQueueCapacity(10);
executor.setThreadNamePrefix("AsynchThread-");
executor.setAllowCoreThreadTimeOut(true);
executor.setKeepAliveSeconds(10);
executor.initialize();
return executor;
}
Then you can define your REST endpoint as follows
然后您可以按如下方式定义您的 REST 端点
@Async("asyncExec")
@PostMapping("/delayedService")
public CompletableFuture<String> doDelay()
{
String response = service.callDelayedService();
return CompletableFuture.completedFuture(response);
}
回答by Zon
A fresh answer for Spring Boot 2.2is required as server.connection-timeout=5000
is deprecated. Each server behaves differently, so server specific properties are recommended instead.
Spring Boot 2.2 的新答案是必需的,因为server.connection-timeout=5000
已弃用。每个服务器的行为都不同,因此建议改为推荐服务器特定的属性。
SpringBoot embeds Tomcat by default, if you haven't reconfigured it with Jetty or something else. Use server specific application propertieslike server.tomcat.connection-timeout
or server.jetty.idle-timeout
.
SpringBoot 默认嵌入了 Tomcat,如果你还没有用 Jetty 或其他东西重新配置它。使用服务器特定的应用程序属性,如server.tomcat.connection-timeout
或server.jetty.idle-timeout
。