Spring restTemplate timeout without throwing exceptioin - spring

I found a timeout issue on my backend service: SA.
SA send request to 3party api with restTemplate:
try {
log.info("sending request to sb"); //position 1
return restTemplate.postForObject("https://url.to.sb.com", null, String.class);
}catch(Exception ex) {
log.error("request error", ex) //position 2
}
The sb service is working normally.
Browser get gateway timeout error .
Logs on position 1 is printed but position 2 is not printed.
Here is how I compose the restTemplate:
RestTemplate restTemplate = new RestTemplate();
HttpClientBuilder httpClientBuilder = HttpClients.custom();
httpClientBuilder.setSSLContext(xxxx);
CloseableHttpClient client = httpClientBuilder.build();
restTemplate.setInterceptors(Arrays.asList(new DefaultHttpRequestInterceptor()));
HttpComponentsClientHttpRequestFactory requestFactory = new
HttpComponentsClientHttpRequestFactory(client);
restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(requestFactory));
return restTemplate;
Why frontend get gateway timeout, but there isn't error log on SA ?
Seems that thread is pending. And this issue is resolved after restart SA .
But I still want to know the possible causes of this issue,
not sure it's related with requestFactory setTimeout

Related

http calls blocked on spring resttemplates with completablefuture

I have a rest endpoint exposed to get data from multiple systems using rest web services. all are independent calls queried using the single primary key with Spring resttemplate.
I used CompletableFuture to call each API first then at end waiting for their response. here in log I do see the calls happened up to the resttemplate exchange methods are happening in parallel but once after that each threads are going in sequential or waiting for another thread to complete.
`CompletableFuture<TypeA> callA = CompletableFuture
.supplyAsync(() -> getCallA(id),
traceableExecutorService);
CompletableFuture<TypeB> callB = CompletableFuture
.supplyAsync(() -> getCallB(id),
traceableExecutorService);
CompletableFuture<TypeC> callC = CompletableFuture
.supplyAsync(() -> getCallC(id),
traceableExecutorService);
try {
TypeA = callA.get();
TypeB = callB.get();
TypeC = callC.get();
} catch (InterruptedException | ExecutionException e) {
throw e;
}
// code create response and return...
`
rest template config
`
#Bean
public RestTemplate restTemplate() {
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
httpClientBuilder.setRetryHandler(
new DefaultHttpRequestRetryHandler(3, true));
httpClientBuilder.setDefaultRequestConfig(RequestConfig.custom()
.setConnectionRequestTimeout(10000)
.setSocketTimeout(10000).build());
httpClientBuilder.setMaxConnTotal(2000);
httpClientBuilder.setMaxConnPerRoute(100);
HttpClient httpClient = httpClientBuilder.build();
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(
httpClient);
clientHttpRequestFactory.setConnectTimeout(10000);
clientHttpRequestFactory.setReadTimeout(10000);
RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory(clientHttpRequestFactory);
restTemplate.setInterceptors(Collections.singletonList(new RequestResponseLoggingInterceptor()));
return restTemplate;
}
`
thread pool
new TraceableExecutorService(factory, Executors.newWorkStealingPool(20000))

Rest Template release Connection from Pool

I have rest template config similar to the following. I am trying to release a connection from the pool if I get a status code that does not equal 2XX (long story but need this code). Is here a way I can get the connection Manager and release a specific connection?
#Bean
public RestTemplate restTemplate() {
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(100);
connectionManager.setDefaultMaxPerRoute(20);
RequestConfig requestConfig = RequestConfig
.custom()
.setConnectionRequestTimeout(5000) // timeout to get connection from pool
.setSocketTimeout(5000) // standard connection timeout
.setConnectTimeout(5000) // standard connection timeout
.build();
HttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(connectionManager)
.setDefaultRequestConfig(requestConfig).build();
ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
return new RestTemplate(requestFactory);
}
Looking for a way to accomplish something similar to the following
if(!httpStatusCode.substr(1).equals("2")) {
restTemplate.getConnectionPool().relase().thisConnection();
}
enter code here

Socket timeout not working in Rest template third party API call - Spring boot

I am trying to test response-time out by configuring socket time out when third party rest service call. I am calling external web service by Spring Rest Template in my service.
For response timeout testing purpose, the external web service is taking more time which I configured.
I have configured 1600 milliseconds for timeout, but unfortunately I am getting response in more then configured time, around 2500 - 3000 milliseconds.
As per the configuration I should get time out exception.
public ClientHttpRequestFactory getClientHttpRequestFactory(String timeout) {
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(Integer.parseInt(timeout))
.setConnectionRequestTimeout(Integer.parseInt(timeout))
.setSocketTimeout(Integer.parseInt(timeout))
.build();
CloseableHttpClient closeableHttpClient = HttpClientBuilder.create()
.setDefaultRequestConfig(requestConfig)
.build();
return new HttpComponentsClientHttpRequestFactory(closeableHttpClient);
}
public String milisecTimeout = "1600";
RestTemplate restTemplate = new RestTemplate(appConfig.getClientHttpRequestFactory(milisecTimeout));
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("Content-Type", "application/json");
httpHeaders.set("Accept", "application/json");
httpHeaders.set("Accept-Charset", "UTF-8");
HttpEntity<String> httpEntity = new HttpEntity<>(request, httpHeaders);
String responseBody = "";
try {
ResponseEntity<String> response = restTemplate.exchange(hostUrl, HttpMethod.POST, httpEntity, String.class);
String statusCode = response.getStatusCodeValue();
String responseBody = response.getBody();
SearchRS searchSdnRS = objectMapper.readValue(responseBody, SearchRS.class);
} catch (Exception ex){
log.error("Error:", ex.getCause());
}
Please correct me if any misunderstanding.
Socket timeout is defined as maximum time of inactivity between two data packets. It's not about total request duration. So in the case you're describing it could well be that the data transfer from server to client started after 1500 milliseconds and lasted 1000–1500 milliseconds.

RestTemplate call returns 401 Unauthorized

Background
I am trying to consume a REST endpoint hosted on IBM Cloud API from my SpringBoot application using RestTemplate. I am using the following snippet to make the call:
RestTemplate send = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setCacheControl(CacheControl.noCache());
headers.set("x-ibm-client-id", clientId);
headers.set("x-ibm-client-secret", clientSecret);
HttpEntity<BodyEntity> httpEntity = new HttpEntity<>(bodyEntity, headers);
send.exchange(ENDPOINT_URL, HttpMethod.POST, httpEntity, Object.class);
I used the following snippet to configure RestTemplate
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
Problem
Using this snippet, when the call is made I receive 401 Unauthorized. When I made the same call using Postman, I received correct response from server without any problem.
Since I received 401 response code I set to further investigate the request by logging headers and body and other parts of request.
I implemented ClientHttpRequestInterceptor to log outgoing requests to further debug the issue and added this interceptor to my RestTemplate config as follows:
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
// new code
builder.interceptors(new LoggingClientHttpRequestInterceptor());
return builder.build();
}
After making the request again, I could see in the log that the outgoing call contained all details as it should e.g. Headers and Body were correct.
After this, I changed the whole thing to use Apache HTTP Client as follows:
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(URL);
String reqString = "BODY";
httpPost.setEntity(new StringEntity(reqString, ContentType.APPLICATION_JSON));
httpPost.setHeader("accept", "application/json");
httpPost.setHeader("content-type", "application/json");
httpPost.setHeader("cache-control", "no-cache");
httpPost.setHeader("x-ibm-client-id", clientId);
httpPost.setHeader("x-ibm-client-secret", clientSecret);
CloseableHttpResponse response = httpClient.execute(httpPost);
try {
System.out.println("Response status: " + response.getStatusLine());
HttpEntity entity1 = response.getEntity();
System.out.println("Response :" + entity1.toString());
} finally {
response.close();
}
Using the snippet above, I executed the request and received correct response.
Question
Why RestTemplate call returns and error whereas HttpClient returns correct response?
Do I need to further configure RestTemplate?
What have I missed?

java.lang.IllegalArgumentException: Comparison method violates its general contract! in Spring Rest Template

I am facing a weird issue while calling a REST url using Spring's RestTemplate.I am using Spring Boot.
The error is occurring only after approx 10 to 15 successful calls and thereafter erratically. I can smoothly exchange data before the error, in the first 1 to 15 calls approx. Url is like someresturl/param1/param2/param3.
public ResponseEntity<String> callRestUrl(CustomReqClass req) {
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
StringBuilder url = new StringBuilder("someresturl");
finishTaskUrl.append("/").append(param1).append("/").append(param2).append("/").append(param3);
ResponseEntity<String> response = null;
HttpEntity<CustomReqClass> request = new HttpEntity<CustomReqClass>(req, getHTTPHeaders());
try {
//first approach
response = restTemplate.postForEntity(url.toString(), request, String.class, Collections.<String, String>emptyMap());
//second approach
response = restTemplate.exchange(url.toString(), HttpMethod.POST, request, String.class);
} catch (Exception e) {
LOGGER.info("Error calling url" + e);
}
return response;
}
public MultiValueMap<String, String> getHTTPHeaders() {
MultiValueMap<String, String> headers = new LinkedMultiValueMap<String, String>();
headers.add("Authorization", "Basic authabcdxyz");
headers.add("Content-Type", "application/json");
return headers;
}
Here I am autowiring restTemplate object in the class where I am using this.
I have tried both the above methods postForEntity and exchange of Rest template. Error is occurring for both.
The exception I am getting after first few successful attempts:
java.lang.IllegalArgumentException: Comparison method violates its general contract!
As an additional thought, the above piece of code is being scheduled by Spring Scheduler mechanism. Is it possible internal threading used in scheduler is causing this issue?

Resources