2016-01-18 27 views
6

Ho un servizio REST di avvio di avvio che a volte richiama servizi di terze parti come parte di una richiesta. Vorrei impostare un timeout su tutte le mie risorse (diciamo 5 secondi), in modo tale che se una qualsiasi richiesta di gestione (l'intera catena, dall'arrivo alla risposta) impiega più di 5 secondi, i miei controller rispondono con HTTP 503 invece della risposta effettiva . Sarebbe fantastico se questo era solo una proprietà di Primavera, per l'impostazioneSpring REST API - richiesta timeout?

spring.mvc.async.request-timeout=5000 

esempio, ma non ho avuto fortuna con quello. Ho anche provato estendere WebMvcConfigurationSupport e configureAsyncSupport prioritario:

@Override 
public void configureAsyncSupport(final AsyncSupportConfigurer configurer) { 
    configurer.setDefaultTimeout(5000); 
    configurer.registerCallableInterceptors(timeoutInterceptor()); 
} 

@Bean 
public TimeoutCallableProcessingInterceptor timeoutInterceptor() { 
    return new TimeoutCallableProcessingInterceptor(); 
} 

senza alcuna fortuna.

Sospetto di dover eseguire manualmente manualmente tutte le chiamate di terze parti e, se impiegano troppo tempo, lanciare un'eccezione di timeout. È giusto? O c'è una soluzione olistica più semplice che copre tutti i miei endpoint di richiesta?

risposta

9

è necessario restituire un Callabe se si desidera spring.mvc.async.request-timeout=5000 a lavoro.

@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"; 
     } 
    }; 
} 
+3

Se si utilizza Java 8, può anche utilizzare l'espressione Lamba: 'return() -> {/ * fai le tue cose qui * /}'; – demaniak

2

se si utilizza RestTemplate quanto deve utilizzare codice seguente per implementare timeout

@Bean 
public RestTemplate restTemplate() { 
    return new RestTemplate(clientHttpRequestFactory()); 
} 

private ClientHttpRequestFactory clientHttpRequestFactory() { 
    HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(); 
    factory.setReadTimeout(2000); 
    factory.setConnectTimeout(2000); 
    return factory; 
}} 

La configurazione 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> 

1

vorrei suggerire di dare un'occhiata al motorino di avviamento Primavera cloud Netflix Hystrix per gestire le chiamate remote/lente potenzialmente inaffidabili. Implementa il pattern Circuit Breaker, inteso proprio per questo genere di cose.

Vedere offcial docs for more information.

+1

Non capisco perché è stato downvoted, mi sembra che implementare il pattern dell'interruttore è la migliore risposta. Altrimenti, semplicemente restituendo un 503 lasciando la richiesta in esecuzione, probabilmente si sprecano risorse – Jeremie

0

È possibile provare server.connection-timeout=5000 nell'applicazione.proprietà. Dal official documentation:

server.connection-timeout = # Tempo in millisecondi che i connettori saranno attendere un'altra richiesta HTTP prima di chiudere la connessione. Se non è impostato , verrà utilizzato il valore predefinito specifico del contenitore. Utilizzare un valore di -1 per indicare il timeout no (cioè infinito).

D'altra parte, si può decidere di gestire i timeout sul lato client utilizzando Circuito modello Breaker come ho già descritto nella mia risposta qui: https://stackoverflow.com/a/44484579/2328781