繁体   English   中英

如何在 Spring Boot REST API 上设置超时?

[英]How to set a timeout on a Spring Boot REST API?

我有一些 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
}

看起来您正在描述断路器模式 如果您可以控制客户端和服务器代码,并且想要探索 Spring Cloud 和 Netflix Hysterix 库,您可以查看入门:断路器指南。

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

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

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

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

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

您可以设置此属性配置

 server.connection-timeout=30000 

在您的 application.properties 中。 根据官方文档说:

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

使用 Spring Boot 2.3 / Tomcat 9,您可以通过安装 Tomcat StuckThreadDetectionValve所有传入的 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

您可以使用未来超时:

final Future<Object> submit = service.submit(new Callable<Object>() {
    @Override
    public Object call() throws Exception {
        ......YOUR CODE
        return "";
    }
});
try {
    submit.get(3, TimeUnit.SECONDS);
} catch (Exception e) {
    log.error("fail",e);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM