Spring Boot REST API - 请求超时



我有一个Spring Boot REST服务,有时会调用第三方服务作为请求的一部分。我想在我的所有资源上设置超时(假设 5 秒),这样如果任何请求处理(从传入到响应的整个链)花费的时间超过 5 秒,我的控制器将使用 HTTP 503 而不是实际响应进行响应。如果这只是一个 Spring 属性,例如设置

spring.mvc.async.request-timeout=5000

但我没有任何运气。我还尝试扩展WebMvcConfigurationSupport并覆盖configureAsyncSupport:

@Override
public void configureAsyncSupport(final AsyncSupportConfigurer configurer) {
    configurer.setDefaultTimeout(5000);
    configurer.registerCallableInterceptors(timeoutInterceptor());
}
@Bean
public TimeoutCallableProcessingInterceptor timeoutInterceptor() {
    return new TimeoutCallableProcessingInterceptor();
}

没有任何运气。

怀疑我必须手动计时所有第三方调用,如果它们花费的时间太长,请抛出超时异常。是吗?或者是否有任何更简单的整体解决方案可以涵盖我的所有请求端点?

如果您希望spring.mvc.async.request-timeout=5000工作,则需要返回Callable<>

@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";
        }
    };
}

Spring Boot 2.2 需要一个新的答案,因为server.connection-timeout=5000已被弃用。每个服务器的行为不同,因此建议改为使用特定于服务器的属性。

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

正如威尔金森评论的那样:

设置连接超时只会导致超时,当客户端连接,但速度太慢,无法发送其请求。如果需要帮助,客户端最多等待 30 秒的响应,您将必须在客户端进行配置。如果你想要服务器端最多只花费 30 秒来处理请求,则没有保证的方法,因为你不能强制正在处理的线程停止请求。

您也可以尝试设置spring.mvc.async.request-timeout

@Transactional 注释采用超时参数,您可以在该参数中为@RestController中的特定方法指定超时(以秒为单位)

@RequestMapping(value = "/method",
    method = RequestMethod.POST,
    produces = MediaType.APPLICATION_JSON_VALUE)
@Timed
@Transactional(timeout = 120)

我建议你看看Spring Cloud Netflix Hystrix入门,以处理可能不可靠/缓慢的远程呼叫。它实现了断路器模式,该模式正是针对此类事情的。

有关详细信息,请参阅官方文档。

您可以在 application.properties 中尝试server.connection-timeout=5000。来自官方文档:

server.connection-timeout= # 连接器将花费的时间(以毫秒为单位) 在关闭连接之前等待另一个 HTTP 请求。当不是 设置后,将使用连接器特定于容器的默认值。使用 值为 -1 表示无(即无限)超时。

另一方面,您可能希望使用断路器模式处理客户端的超时,正如我在此处的回答中已经描述的那样:https://stackoverflow.com/a/44484579/2328781

如果您使用的是 RestTemplate,则应使用以下代码来实现超时

@Bean
public RestTemplate restTemplate() {
    return new RestTemplate(clientHttpRequestFactory());
}
private ClientHttpRequestFactory clientHttpRequestFactory() {
    HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
    factory.setReadTimeout(2000);
    factory.setConnectTimeout(2000);
    return factory;
}}

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>

在 Spring 属性文件中,您不能只为此属性指定一个数字。您还需要指定单位。所以你可以说 spring.mvc.async.request-timeout=5000msspring.mvc.async.request-timeout=5s ,两者都会给你 5 秒的超时。

我觉得

没有一个答案能真正解决问题。我认为您需要告诉Spring Boot的嵌入式服务器处理请求的最长时间应该是多少。我们究竟如何做到这一点取决于所使用的嵌入式服务器的类型。

在暗流的情况下,可以这样做:

@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)
        })
    }
}

春季启动官方文档:https://docs.spring.io/spring-boot/docs/2.2.0.RELEASE/reference/html/howto.html#howto-configure-webserver

您可以为 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;
}

然后,您可以按如下方式定义 REST 终端节点

@Async("asyncExec")
@PostMapping("/delayedService")
public CompletableFuture<String> doDelay()
{ 
    String response = service.callDelayedService();
    return CompletableFuture.completedFuture(response);
}

相关内容

  • 没有找到相关文章

最新更新