Spring Boot REST API - délai d'expiration de la demande?
J'ai un Spring Boot REST qui appelle parfois des services tiers dans le cadre d'une demande. Je voudrais définir un délai d'expiration sur toutes mes ressources (disons 5 secondes), de sorte que si toute gestion des demandes (toute la chaîne, de l'entrée à la réponse) prend plus de 5 secondes, mes contrôleurs répondent avec HTTP 503 au lieu de la réponse réelle. Ce serait génial si ce n'était qu'une propriété Spring, par exemple la configuration
spring.mvc.async.request-timeout=5000
mais je n'ai pas eu de chance avec ça. J'ai également essayé d'étendre WebMvcConfigurationSupport et de remplacer configureAsyncSupport:
@Override
public void configureAsyncSupport(final AsyncSupportConfigurer configurer) {
configurer.setDefaultTimeout(5000);
configurer.registerCallableInterceptors(timeoutInterceptor());
}
@Bean
public TimeoutCallableProcessingInterceptor timeoutInterceptor() {
return new TimeoutCallableProcessingInterceptor();
}
sans aucune chance.
Je soupçonne que je dois chronométrer manuellement tous mes appels tiers, et s'ils prennent trop de temps, lever une exception de délai d'attente. Est-ce correct? Ou existe-t-il une solution holistique plus simple qui couvre tous mes points de terminaison de demande?
Vous devez renvoyer un Callable<>
si tu veux spring.mvc.async.request-timeout=5000
travailler.
@RequestMapping(method = RequestMethod.GET)
public Callable<String> getFoobar() throws InterruptedException {
return new Callable<String>() {
@Override
public String call() throws Exception {
Thread.sleep(8000); //this will cause a timeout
return "foobar";
}
};
}
L'annotation @Transactional prend un paramètre de délai d'expiration où vous pouvez spécifier le délai d'expiration en secondes pour une méthode spécifique dans @RestController
@RequestMapping(value = "/method",
method = RequestMethod.POST,
produces = MediaType.APPLICATION_JSON_VALUE)
@Timed
@Transactional(timeout = 120)
Tu peux essayer server.connection-timeout=5000
dans votre application.properties. De la documentation officielle :
server.connection-timeout = # Temps en millisecondes pendant lequel les connecteurs attendront une autre requête HTTP avant de fermer la connexion. Lorsqu'il n'est pas défini, la valeur par défaut spécifique au conteneur du connecteur sera utilisée. Utilisez une valeur de -1 pour indiquer aucun délai d'attente (c'est-à-dire infini).
D'un autre côté, vous souhaiterez peut-être gérer les délais d'attente côté client en utilisant le modèle de disjoncteur comme je l'ai déjà décrit dans ma réponse ici: https://stackoverflow.com/a/44484579/2328781
si vous utilisez RestTemplate, vous devez utiliser le code suivant pour implémenter les délais d'expiration
@Bean
public RestTemplate restTemplate() {
return new RestTemplate(clientHttpRequestFactory());
}
private ClientHttpRequestFactory clientHttpRequestFactory() {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setReadTimeout(2000);
factory.setConnectTimeout(2000);
return factory;
}}
La configuration 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>
Je vous suggère de jeter un œil au démarreur Spring Cloud Netflix Hystrix pour gérer les appels distants potentiellement peu fiables/lents. Il implémente le modèle de disjoncteur, qui est précisément destiné à cette chose sorta.