http calls blocked on spring resttemplates with completablefuture - spring-boot

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))

Related

Pact consumer test does not successfully mock the spring webclient request using the created pact

I am new to Pact Contract testing and I am trying to create a Pact consumer test to validate a method that calls an api with get request. The api request is made using Spring Webclient.
I am not able to create the webclient object by just providing the Pact mockserver eg.
WebClient webClient = WebClient.builder().baseUrl(mockServer.getUrl()).build();
I am getting the exception java.lang.IllegalStateException: No suitable default ClientHttpConnector found. The explanation I get on the internet for that , is to include reactor-netty-http and I was able to get past this issue when i included that in the POM. But I don't think that is the right solution here because I need the mockserver to respond to the webclient request and it is not. Has anyone dealt with this issue before or am I doing this wrong?
Here is the code snippet:
public RequestResponsePact pactMethod(PactDslWithProvider builder) {
Map<String, String> headers = new HashMap<>();
headers.put(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
return builder.given("Consumer request")
.uponReceiving(" getResource call")
.path("/path")
.method("GET")
.willRespondWith()
.status(200)
.headers(headers)
.body(RESPONSE_JSON).toPact();
}
#Test
#PactTestFor(pactMethod = "pactMethod", port = "9999")
public void consumerTest(MockServer mockServer) {
WebClient webClient = WebClient.builder().baseUrl(mockServer.getUrl()).build();
ConsumerServiceClient consumerServiceClient = new ConsumerServiceClient(webClient);
Mono<Data> data = consumerServiceClient.getData();
StepVerifier.create(data)
.assertNext(resp -> {
try {
Value value = resp.getValue();
Assertions.assertFalse( value.isEmpty());
} catch (Exception e) {
log.error("Unable to convert response to Value", e);
Assertions.fail();
}
}).expectComplete()
.verify();
}
The webclient call:
webClient.get()
.uri("/path")
.retrieve()
.onStatus(status -> status == HttpStatus.NOT_FOUND,
res -> Mono.error(new RunTimeException()))
.bodyToMono(clazz);

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.

How to call a microservice to fetch data in spring webflux

I want to call a microservice from another service using webclient in spring flux. But, I am not able to write the code properly. Can you please suggest how to call another service. Please find my code as below.
I need to call the below service
public Mono<ServerResponse> load(ServerRequest res){
String c1name = res.pathVariable("cust");
String c2name = res.queryParam("cl").orElse("");
String oname = res.queryParam("ol").orElse("");
return res.body()
}
public Mono<ResponseEntity<Void>> ftpFileSend(MultipartFile fileData, String cust, MultiValueMap<String,String) qpar {
MultiValueMap<String,String> qpar=new LinkedMultiValueMap<String,String>();
qpar.add("name","spring");
MultiValueMap<String,Object> body=new LinkedMultiValueMap<String,Object>();
String url="http://localhost:8088/"+ cust+"/load";
try {
body.add("file", fileData.getBytes());
} catch (IOException e) {
return Mono.error(e); // <-- note how to create an error signal
}
return webClient
.post()
.uri(uriBuilder -> uriBuilder.path(url).queryParams(qpar).build() )
.contentType(MediaType.MULTIPART_FORM_DATA)
.body(BodyInserters.fromMultipartData(body))
.retrieve()
.toBodilessEntity();
}
Hmm it would be great if you have provided some error logs or so. Anyway if you want to create a multipart body there is a builder, MultipartBodyBuilder (in org.springframework.http.client.MultipartBodyBuilder).
Example usage is as follows,
MultipartBodyBuilder builder = new MultipartBodyBuilder();
builder.part("file", new MultipartFileResource(fileData));
MultiValueMap<String, HttpEntity<?>> multipartBody = builder.build();
Then use this multipartBody in webClient call.
return webClient
...
.body(BodyInserters.fromMultipartData(multipartBody))
.retrieve()
.toBodilessEntity();

Spring restTemplate timeout without throwing exceptioin

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

Hystrix-javanica #fallbackMethod Last Cached Response

I'm looking to do something like the following:
#HystrixCommand(fallbackMethod = "returnLastGoodCachedCopy")
void performRequest(String someArg) {
// Make HTTP request using RestTemplate configured with EHCache
}
void returnLastGoodCachedCopy(String someArg) {
// Return the last successful response
}
For a little more background I am using Spring Boot, and setting up the RestTemplate like so to use EHCache:
#Bean
public RestTemplate restTemplate() {
return new RestTemplate(clientHttpRequestFactory());
}
#Bean
public CloseableHttpClient httpClient() {
CacheConfig cacheConfig = CacheConfig.custom()
.setMaxCacheEntries(this.httpClientProperties.getMaxCacheEntries())
.setMaxObjectSize(this.httpClientProperties.getMaxObjectSize())
.setHeuristicCachingEnabled(this.httpClientProperties.getHeuristicLifetimeEnabled())
.setHeuristicDefaultLifetime(this.httpClientProperties.getHeuristicLifetimeSeconds()).build();
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(this.httpClientProperties.getConnectTimeout())
.setSocketTimeout(this.httpClientProperties.getSocketTimeout()).build();
Ehcache httpEhcache = (Ehcache) this.ehCacheManager.getCache(httpClientProperties.getCacheName())
.getNativeCache();
EhcacheHttpCacheStorage ehcacheHttpCacheStorage = new EhcacheHttpCacheStorage(httpEhcache);
CloseableHttpClient cachingClient = CachingHttpClients.custom().setCacheConfig(cacheConfig)
.setHttpCacheStorage(ehcacheHttpCacheStorage).setDefaultRequestConfig(requestConfig).build();
return cachingClient;
}
private ClientHttpRequestFactory clientHttpRequestFactory() {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient());
return factory;
}
So my one thought was to use the same request EHCache, but I'm not sure that's an appropriate solution considering that cache is based on cache-control headers, which I'd like to be separated from so I can return a valid response regardless if it is expired or not.
My other thought was to configure a separate EHCache cache, and store the responses myself, then I can access those more easily considering I set the format of the key and the value.
Before I go down this path I want to see if there is already anything built into Hystrix that handles this situation, or if there are any other recommended approaches.

Resources