[英]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.