Spring Rest template weird time out exception - spring

I am using Spring rest template to generate a REST call to a server.
from the application, it returns
I/O error on GET request for "http://XX.XX.XX.XX/v1/api":Connect to XX.XX.XX.XX:80 [/XX.XX.XX.XX] failed: connect timed out"
But if I use the browser I get the DATA perfectly.
This is the configuration:
#Bean
public RestTemplate restTemplate() {
return new RestTemplate(clientHttpRequestFactory());
}
What can be the problem?
Thanks

Related

Spring rest template close connection if the data is more

I have a scenario where the http connection needs to be closed if the server is sending more data than expected. i.e after a few seconds of receiving the data, I would like the close the connection automatically. Is this feasible?
You can specify a timeout on your RestTemplate. That way you can terminate any long running requests.
#Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder)
{
return restTemplateBuilder
.setConnectTimeout(...)
.setReadTimeout(...)
.build();
}

Eureka server and UnknownHostException

I have installed an Eureka server and have registered a service called pricing-service.
The Eureka dashboard shows
UP pricing-service:4ac78ca47bdbebb5fec98345c6232af0
under status.
Now I have a completely separate Spring boot web service which calls (through a WebClient instance) the pricing-service as http://pricing-service but I get "reactor.core.Exceptions$ReactiveException: java.net.UnknownHostException: No such host is known (pricing-service)"
exception.
So the Controller can't find the pricing-service by hostname.Further, how is the controller aware of the Eureka server in order to get to pricing-service? Shouldn't there be a reference to it in the application.properties of the web service? I couldn't find anything around the web.
WebClient doesn't know anything about Eureka out of the box. You need to use #LoadBalancerClient and #LoadBalanced to wire it up through the load balancer. See the docs here:
https://spring.io/guides/gs/spring-cloud-loadbalancer/
Now I have a completely separate Spring boot web service which calls (through a WebClient instance) the pricing-service as http://pricing-service
This separate service (the WebClient Service) of yours must also register itself with Eureka Server.
By default, webclient is not aware of having to use load-balancer to make calls to other eureka instances.
Here is one of the ways to enable such a WebClient bean:
#Configuration
public class MyBeanConfig {
#Bean
WebClient webClient(LoadBalancerClient lbClient) {
return WebClient.builder()
.filter(new LoadBalancerExchangeFilterFunction(lbClient))
.build();
}
}
Then, you can use this webClient bean to make calls as:
#Component
public class YourClient {
#Autowired
WebClient webClient;
public Mono<ResponseDto> makeCall() {
return webClient
.get()
.uri("http://pricing-service/")
// <-- change your body and subscribe to result
}
Note: Initializing a Bean of WebClient can be explored further here.
I had the issue that WebClient was not working with #LoadBalanced for me when I created a bean that returned WebClient. You have to create a bean for WebClient.Builder instead of just WebClient, otherwise the #LoadBalanced annotation is not working properly.
#Configuration
public class WebClientConfig {
#Bean
#LoadBalanced
public WebClient.Builder loadBalancedWebClientBuilder() {
return WebClient.builder();
}
}

How implement Error decoder for multiple feign clients

I have multiple feign clients in a Spring Boot application. I am using a Controller Advice for handling custom exceptions for each feign client.
Here my controller advice that handles two custom exceptions (one for each client: client1 and client2):
#ControllerAdvice
public class ExceptionTranslator implements ProblemHandling {
#ExceptionHandler
public ResponseEntity<Problem> handleCustomClient1Exception(CustomException1 ex, NativeWebRequest request) {
Problem problem = Problem.builder()
.title(ex.getTitle())
.detail(ex.getMessage())
.status(ex.getStatusType())
.code(ex.getCode())
.build();
return create(ex, problem, request);
}
#ExceptionHandler
public ResponseEntity<Problem> handleCustomClient2Exception(CustomException2 ex, NativeWebRequest request) {
Problem problem = Problem.builder()
.title(ex.getTitle())
.detail(ex.getMessage())
.status(ex.getStatusType())
.code(ex.getCode())
.build();
return create(ex, problem, request);
}
}
I have implemented an error decoder for feign client1.
public class ClientErrorDecoder implements ErrorDecoder {
final ObjectMapper mapper;
public ClientErrorDecoder() {
this.mapper = new ObjectMapper();
}
#Override
public Exception decode(String methodKey, Response response) {
ExceptionDTO exceptionDTO;
try {
exceptionDTO = mapper.readValue(response.body().asInputStream(), ExceptionDTO.class);
} catch (IOException e) {
throw new RuntimeException("Failed to process response body.", e);
}
return new CustomException1(exceptionDTO.getDetail(), exceptionDTO.getCode(), exceptionDTO.getTitle(), exceptionDTO.getStatus());
}
}
I have also configured feign for using that error decoder for that specific client like this:
feign:
client:
config:
client1:
errorDecoder: feign.codec.ErrorDecoder.Default
My question is: what is the best approach for handling more than one feign client exceptions? Should I use the same error decoder and treat their responses as a generic exception? Or should I create an error decoder for each feign client?
Quick Answer
If you work with different APIs, error responses will not be formatted the same way. Hence handling them separately seems to be the best approach.
Remarks
From your example, it seems like you defined a custom ErrorDecoder that may
be not used because you also configured feign to use default error decoder for you client1 in properties file.
Even if you defined a #Configuration class somewhere with a bean for your custom ClientErrorDecoder,
Spring Cloud documentation mentions that configuration properties take precedence over #Configuration annotation
If we create both #Configuration bean and configuration properties,
configuration properties will win. It will override #Configuration
values. But if you want to change the priority to #Configuration, you
can change feign.client.default-to-properties to false.
Example
Here is a hypothetical pruned configuration to handle multiple feign clients with different error decoders :
Client1:
You tell feign to load beans defined in CustomFeignConfiguration class for client1
#FeignClient(name = "client1", configuration = {CustomFeignConfiguration.class})
public interface Client1 {...}
Client2:
Client2 will use default Feign ErrorDecoder because no configuration is specified. (Will throw a FeignException on error)
#FeignClient(name = "client2")
public interface Client2 {...}
Configuration: Be carefull here, if you add #Configuration to CustomFeignConfiguration, then ClientErrorDecoder bean will be used for every loaded feign clients (depending on your application component scanning behaviour)
public class CustomFeignConfiguration {
#Bean
public ClientErrorDecoder clientErrorDecoder(ObjectMapper objectMapper) {
return new ClientErrorDecoder(objectMapper);
}
}
This configuration could be done with properties file aswell.
Side remark
From my point of view, you don't even need controller advice. If you use Spring Web #ResponseStatus annotation, you can tell which HTTP status code should be sent back with exception body thrown by your custom ErrorDecoder.
Helpeful resources
Spring Cloud Documentation
GitHub issue related to the subject

Spring Boot RestTemplate random ResourceAccessException: Connection reset errors

I have a system that implements 4 micro-services. The four services need to occasionally share information and they do it via RESTful requests using Spring's RestTemplate. Currently about 5%-10% of the requests fail with an exception like:
org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://otherservice.com/path": Connection reset; nested exception is java.net.SocketException: Connection reset
Again, this appears random and only fails about 5%-10% of the time. I have tried multiple things but nothing seems to work. Currently I am trying this:
Configuration:
#Configuration
public class BeanConfiguration {
#Bean
public RestTemplate restTemplate() {
ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(HttpClients.createDefault());
return new RestTemplate(requestFactory);
}
}
Service:
#Autowired
public MyService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public Contact addContact(Contact contact) {
HttpEntity<Contact> entity = new HttpEntity<>(contact, authenticationTokenInfo.setTokenHeaders());
ResponseEntity<Contact> response = restTemplate.exchange(contact_base_url, HttpMethod.POST, entity, Contact.class);
return response.getBody();
}
I have tried a number of different approaches and nothing has made any difference. I tried this for example:
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
I am logging all of the requests in each of my micro-services and it doesn't appear that the requests are actually hitting the other services. They just fail. According to the logs they fail in less than 50 ms so it isn't a timeout issue. For a couple of them I have implemented an exponential back-off retry but that isn't really a viable solution.
I also faced with same problem. Seems like the problem is with idle connections in pool.
This resolve problem in my case and no any error occasionally occurred
HttpClient httpClient = HttpClients
.custom()
.evictIdleConnections(60000, TimeUnit.MILLISECONDS)
.build();
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);

How to expose both a SOAP web-service and RESTful API at the same time in Spring Boot?

In Spring Boot 1.4.3 I exposed a SOAP web service endpoint which works successfully on port 8080.
For the purpose of running a health check I also need to expose a RESTful API. I tried both using Actuator and a rest controller:
#RestController
public class RESTapis {
#RequestMapping(method = {RequestMethod.GET, RequestMethod.POST}, value = "/health")
public String healthCheck() {
return "ACK";
}
}
but in both cases I get the same response: HTTP 405 (method not allowed).
The REST api returns HTTP 200 if I disable the web-service.
How can I have both the SOAP web-service and REST working at the same time?
Here is the web-service configuration:
#EnableWs
#Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
#Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
MessageDispatcherServlet servlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
return new ServletRegistrationBean(servlet, "/*");
}
}
So going off the messageDispatcherServlet method it looks like you are binding your servlet to all the incoming request due to the wildcard registration:
return new ServletRegistrationBean(servlet, "/*");
Hence the MessageDispatcher is intercepting all of your incoming requests and trying to find the /health and throwing http 405.
Fix:
return new ServletRegistrationBean(servlet, "/soap-api/*");
Explanation:
By binding the Message Dispatcher to a specific URI namespace we can ensure that all the request fired on the /soap-api/* namespace ONLY will be intercepted by the MessageDispatcher. And all the other requests will be intercepted by the DispatcherServlet making it possible to run a Rest interface in parallel to your Soap WS.
Suggestion:
Not knowing the reasons / specifics of the app, but going off the name of the method healthcheck(), you can look at using spring boot actuator to generate health checks, metrics for you app. You can also override it for customisations.
Reference for actuator: https://spring.io/guides/gs/actuator-service/

Resources