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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 16:02:39  来源:igfitidea点击:

Spring Boot REST API - request timeout?

javaspringrestspring-boottimeout

提问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=5000to 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 以处理可能不可靠/缓慢的远程调用。它实现了断路器模式,正是为了这种事情。

See offcial docs for more information.

有关更多信息,请参阅官方文档

回答by Danylo Zatorsky

You can try server.connection-timeout=5000in 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=5000msor spring.mvc.async.request-timeout=5s, both of which will give you a 5-second timeout.

在 Spring 属性文件中,您不能只为此属性指定一个数字。您还需要指定一个单位。所以你可以说spring.mvc.async.request-timeout=5000msor 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=5000is 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-timeoutor server.jetty.idle-timeout.

SpringBoot 默认嵌入了 Tomcat,如果你还没有用 Jetty 或其他东西重新配置它。使用服务器特定的应用程序属性,server.tomcat.connection-timeoutserver.jetty.idle-timeout