簡體   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