Spring Boot REST API - 请求超时?

时间:2016-01-18 10:18:06

标签: java spring rest spring-boot timeout

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

,那将是非常棒的
code
但是我还没有运气。我也尝试过扩展WebMvcConfigurationSupport并覆盖configureAsyncSupport:

<h3 id="SectionID">Section With ID</h3>
没有任何运气。

我怀疑我必须手动计算所有第三方呼叫的时间,如果花费的时间太长,则抛出超时异常。是对的吗?或者是否有涵盖我所有请求端点的更简单,整体的解决方案?

10 个答案:

答案 0 :(得分:16)

如果您希望$csv | select vds, protgroup, vlan, ports | Export-Csv $csv正常工作,则需要返回Callable<>

spring.mvc.async.request-timeout=5000

答案 1 :(得分:7)

@Transactional批注带有一个超时参数,您可以在其中为@RestController中的特定方法指定以秒为单位的超时

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

答案 2 :(得分:4)

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

如果尚未使用Jetty或其他工具重新配置,SpringBoot默认会嵌入Tomcat。 使用服务器特定的应用程序属性,例如server.tomcat.connection-timeoutserver.jetty.idle-timeout

答案 3 :(得分:3)

如果您使用的是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>

答案 4 :(得分:3)

Resilience4j TimeLimiter

Resilience4j 是一个主要用于管理远程通信容错的库。它的 TimeLimiter 模块正是我们在这里感兴趣的。

首先,我们必须在我们的项目中包含 resilience4j-timelimiter 依赖项:

<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-timelimiter</artifactId>
    <version>1.6.1</version>
</dependency>

接下来,让我们定义一个简单的 TimeLimiter,它的超时持续时间为 500 毫秒

private TimeLimiter ourTimeLimiter = TimeLimiter.of(TimeLimiterConfig.custom()
  .timeoutDuration(Duration.ofMillis(500)).build());

这可以很容易地从外部配置。

@GetMapping("/author/resilience4j")
public Callable<String> getWithResilience4jTimeLimiter(@RequestParam String title) {
    return TimeLimiter.decorateFutureSupplier(ourTimeLimiter, () ->
      CompletableFuture.supplyAsync(() -> {
        bookRepository.wasteTime();
        return bookRepository.findById(title)
          .map(Book::getAuthor)
          .orElse("No book found for this title.");
    }));
}

TimeLimiter@Transactional 解决方案相比具有多项优势。即,它支持亚秒级精度和超时响应的即时通知。但是,它仍然必须手动包含在所有需要超时的端点中,它需要一些冗长的包装代码,并且它产生的错误仍然是一个通用的 500 HTTP 错误。此外,它需要返回一个 Callable 而不是原始的 String

TimeLimiter 仅包含来自 Resilience4j 的功能子集,并与 Circuit Breaker 模式很好地接口。


您也可以使用注解来声明 TimeLimiter, here you have an example.

您可以阅读完整的documentation of Resilience4j TimeLimiter here.

答案 5 :(得分:2)

我建议您查看Spring Cloud Netflix Hystrix启动器来处理可能不可靠/慢速的远程调用。它实现了断路器模式,适用于这种类型的东西。

请参阅offcial docs for more information

答案 6 :(得分:2)

您可以在application.properties中尝试server.connection-timeout=5000。来自official documentation

  

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

另一方面,您可能希望使用Circuit Breaker模式处理客户端的超时,正如我在此处的回答中所述:https://stackoverflow.com/a/44484579/2328781

答案 7 :(得分:0)

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

对于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官方文档:https://docs.spring.io/spring-boot/docs/2.2.0.RELEASE/reference/html/howto.html#howto-configure-webserver

答案 8 :(得分:0)

您可以为Springboot REST服务配置异步线程执行器。 setKeepAliveSeconds()应该考虑请求链的执行时间。设置ThreadPoolExecutor的keep-alive秒。默认值为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);
}

答案 9 :(得分:-1)

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