【问题标题】:How to set a timeout on a Spring Boot REST API?如何在 Spring Boot REST API 上设置超时?
【发布时间】:2019-06-02 11:42:44
【问题描述】:

我有一些 REST API 可能需要一段时间才能执行,我想限制它们的执行时间。最好,如果 30 秒过去了并且请求没有返回,我想返回一个特定的 HTTP 代码/数据并完全终止该请求。

当前代码:

@RestController
@CrossOrigin(origins = {"*"}, maxAge = 4800, allowCredentials = "false")
public class APIController {

@RequestMapping(value = "/api/myapifunc", method = RequestMethod.POST, produces = "application/json")
public ResponseEntity<?> optimize(@RequestParam(value="param1", defaultValue="")) {
    // Code here
}

【问题讨论】:

  • this post上的一些好答案
  • 为什么不在您正在使用的服务上设置适当的超时和回滚,而不是在不知道中止此类请求的含义的情况下在控制器级别进行全面“杀死”?
  • @jbx - 好问题。我们在该 REST 服务中使用了第三方,这可能需要很长时间才能执行。我对此没有任何控制权,因此我需要中止它以防执行时间过长,以确保此类事务不会导致服务器负载过高。
  • @jbs - 但你的问题让我想到,也许我们应该只限制该特定功能的执行,而不是整个控制器级别。谢谢你的评论,点赞! :)
  • @TomShir 欢呼。如果您使用 Spring 的 RestTemplate,您实际上可以将其配置为超时。 docs.spring.io/spring-boot/docs/current/api/org/springframework/… 如果需要,还有连接超时。如果该服务通常很慢,那么您可能想看看您是否可以并行运行它与您可能执行的不需要它响应的任何其他操作。

标签: java rest spring-boot timeout


【解决方案1】:
@RequestMapping(value = "/api/myapifunc", method = RequestMethod.POST, produces = 
"application/json")
public ResponseEntity<?> optimize(@RequestParam(value="param1", defaultValue="")) {
 return new Callable<String>() {
    @Override
    public String call() throws Exception {
        Thread.sleep(3000); //this will cause a timeout
        return "foobar";
    }
  };
}

未来你可以使用或注释 @Timed @Transactional(timeout = 3000)

【讨论】:

    【解决方案2】:

    您似乎在描述Circuit Breaker pattern。如果您可以控制客户端和服务器代码并想探索 Spring Cloud 和 Netflix Hysterix 库,您可以查看Getting Started: Circuit Breaker 指南。

    如果您使用 Apache Tomcat 作为您的 servlet 容器,您可以配置 Stuck Thread Detection Valve:

    此阀门允许检测需要很长时间才能处理的请求,这可能表明正在处理它的线程被卡住了。此外,它可以选择中断此类线程以尝试解除阻塞。

    当检测到这样的请求时,其线程的当前堆栈跟踪将被写入具有 WARN 级别的 Tomcat 日志。

    卡住线程的 ID 和名称可通过 JMX 在stdThreadIds 和stuckThreadNames 属性中获得。这些 ID 可以与标准 Threading JVM MBean (java.lang:type=Threading) 一起使用,以检索有关每个卡住线程的其他信息。

    【讨论】:

      【解决方案3】:

      你可以设置这个属性配置

       server.connection-timeout=30000 
      

      在您的 application.properties 中。 基于official documentation 说:

      server.connection-timeout= # 连接器在关闭连接之前等待另一个 HTTP 请求的时间。如果未设置,则使用连接器的特定于容器的默认值。使用值 -1 表示没有(即无限)超时。

      【讨论】:

      • 不幸的是,这不起作用。无论如何,谢谢你的时间:)
      • 这不是为了让正在进行的请求超时,而是为了让未接收请求的空闲连接超时。
      【解决方案4】:

      使用 Spring Boot 2.3 / Tomcat 9,您可以通过安装 Tomcat StuckThreadDetectionValveALL 传入的 HTTP 请求设置超时。这是您需要的 Spring 配置代码(它是 Kotlin):

      import org.apache.catalina.valves.StuckThreadDetectionValve
      import org.springframework.beans.factory.annotation.Value
      import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory
      import org.springframework.boot.web.server.WebServerFactoryCustomizer
      import org.springframework.context.annotation.Bean
      import org.springframework.context.annotation.Configuration
      
      @Configuration
      class RequestTimeoutConfiguration(
          @Value("\${app.tomcat.stuck-thread-detection.request-timeout.seconds}")
          private val stuckThreadTimeoutSeconds: Int
      ) {
      
          @Bean
          fun stuckThreadDetectionValve() =
              StuckThreadDetectionValve().apply {
                  threshold = stuckThreadTimeoutSeconds
                  interruptThreadThreshold = stuckThreadTimeoutSeconds
              }
      
          @Bean
          fun stuckThreadDetectionWebServerFactoryCustomizer(valve: StuckThreadDetectionValve) =
              WebServerFactoryCustomizer { factory: TomcatServletWebServerFactory ->
                  factory.addContextValves(valve)
              }
      }
      

      那么你只需要application.properties中的属性来控制它:

      app.tomcat.stuck-thread-detection.request-timeout.seconds=130
      

      【讨论】:

      • 这不适用于我们的请求堆积并且正在等待连接的情况。我不适应等待时间。
      猜你喜欢
      • 2023-03-06
      • 2016-04-23
      • 2018-09-11
      • 2016-08-15
      • 2011-04-11
      • 2021-07-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多