Does the Jersey client close the connection on exception? - jersey

I've read the Jersey documentation, and it says Jersey automatically closes a connection after an entity is read (e.g. response.readEntity(SomeObject.class))
But when an exception is thrown, either a bad request or a socket timeout, does Jersey automatically close the connection, or should I have a finally clause that calls client.close()?

No. Neither does Jersey call client.close() in case of an exception nor does the JerseyClient implement AutoCloseable.
You can easily test this. A client throws a IllegalStateException if you invoke a method after closing:
Client client = ClientBuilder.newClient();
client.close();
client.target("http://stackoverflow.com").request().get(); // IllegalStateException
But you can invoke a method after catching an exception:
Client client = ClientBuilder.newClient();
try {
client.target("http://foo.bar").request().get(); // java.net.ConnectException: Operation timed out
} catch (Exception ex) {
client.target("http://stackoverflow.com").request().get(); // works
}
So closing is your job.
Update: JAX-RS 2.1 will use AutoClosables.

Related

Detect closed communication in Spring Boot Web

I have 2 spring-boot-starter-web services. Service A sends a request via Retrofit to service B. I have configured it to timeout after 10 seconds. Service A detects the timeout (SocketTimeoutException), but I have no way for service B to detect it. How can I verify that the socket is closed? I send a file via outputstream of httpServletResponse and it does not detect that it is closed. It looks like it sends the file to service A, when service A has already timed out.
try (FileInputStream in = new FileInputStream(file)){
OutputStream out = httpServletResponse.getOutputStream();
IOUtils.copy(in,out); // copy from in to out
out.close();
} catch (IOException e) {
// In AWS I get a "broken pipe" IOException. But, locally, I don't get any exception.
}
I don't know if there is a way to check if a Socket is closed until the server tries to read/write from it. I workaround is handle this IOException's like this:
#ExceptionHandler(IOException.class)
#ResponseStatus(HttpStatus.SERVICE_UNAVAILABLE) //(1)
public Object exceptionHandler(IOException e, HttpServletRequest request) {
if (StringUtils.containsIgnoreCase(ExceptionUtils.getRootCauseMessage(e), "Broken pipe")) { //(2)
return null; //(2) socket is closed, cannot return any response
} else {
return new HttpEntity<>(e.getMessage()); //(3)
}
}
This blog post Spring - How to handle "IOException: Broken pipe" can help.

Is there a way to give dynamic timeouts to Rest Template?

I am using Spring Rest template along with apache's PoolingHttpClientConnectionManager for making API calls. The project in which I am working on requires setting custom timeout for each of the HTTP request I make via rest template. In order to achieve this, I am using CompletableFuture with a separate ExecutorService and calling get(Timeout) method.
try{
CompletableFuture<BidResponse> future = CompletableFuture.supplyAsync(() -> bidderService.getBid(), executorService);
bidResponse = future.get(bidderTimeout, TimeUnit.MILLISECONDS);
} catch (InterruptedException | TimeoutException | ExecutionException e) {
bidResponse = getTimeoutBidResponse();
}
Unfortunately, the problem with this approach is that in cases of timeout, the underlying thread keeps on working until the rest template finishes its call. So I am kind of losing out a thread from the thread pool, as well as a connection from the HTTP connection pool.
Is there a way to close the HTTP connection as soon as we receive a Timeout exception, and return the HTTP connection back to the pool ?
p.s. I also tried using Spring Webclient with Mono.timeout. Turns out it actually closes the HTTP connection immediately, but does not return it back to the HTTP pool.
#Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder)
{
return restTemplateBuilder
.setConnectTimeout(...)
.setReadTimeout(...)
.build();
}

Spring JMS MessageListenerAdapter handleListenerException

The default implementation of onMessage in AbstractAdaptableMessageListener does simply:
onMessage(Message message) {
try {
onMessage(message, null);
} catch(Throwable ex) {
handleListenerException(ex);
}
}
Even though the attempt at handling exception is commendable the actual handling in handleListenerException is not sufficient in most cases (it just logs an error level message about the exception). Most real application who would love to make use of the MessageListenerAdapter and simply create a POJO to receive the formatted message have much more granular exception handling requirements.
Why was it done like this and could the onMessage implementation simply be replaced with a call to the onMessage method with a null Session argument and no try catch and simply allow the application to intercept (Java Enterprise interceptor or Spring Aspect) the onMessage JMS method and perform integrated/coherent exception handling? In the past, I have had to subclass MessageListenerAdapter simply to override either the onMessage or handleListenerException method to handle exceptions myself.

How to manage Feign errors?

We are using Spring-boot with Spring-cloud and Spring-cloud-netflix with Spring-cloud-feign.
We are creating our Gateway application that with the help of Feign will try to communicate with our authentication microservice in order to validate their credentials. Here you can see an example of our Feign authentication client:
#FeignClient(value="auth", configuration = AuthClientConfiguration.class)
public interface AuthClient {
#RequestMapping(method = RequestMethod.GET, value = "/tokens", consumes = MediaType.APPLICATION_JSON_VALUE)
Single<Session> getSession(#RequestHeader("Authorization") String token);
}
The question is, how we can deal with all the exceptions that could be raised by the client? I mean, how we can for example catch that a NetworkException or a TimeoutException has been thrown? We've defined our own ErrorDecoder but it appears that this "kind of listener" only works when the request has arrived and the response returned (in our case from authentication client). So, how we can manage this other exceptions?
Best,
Error decoders are decoding HTTP error responses (500, 404, 401, etc...). Exceptions will bubble up in client calls, so using try/catch should work.
try {
return client.home();
} catch (RuntimeException e) {
e.printStackTrace();
throw e;
}

ActiveMQ message ordering - Session rollback for JMSException?

I have a Spring JMS Consumer class that reads messages off a queue (implements SessionAwareMessageListener) and processes them for sending off to a web service. We need to preserve the order in which the messages arrive and are processed, as they contain incremental updates to the same data.
To ensure this, we roll back the Session in the listener in case of any recoverable failure, such as a service timeout, so the same message can be retried again. However, if the message has an invalid format or contains bad data, it is discarded (session is not rolled back).
In case of a JMSException, which is thrown by the message.getText() method, I am not clear if I should roll back the session or not. Can this be considered a recoverable error or should the message be discarded in case this error occurs?
The code looks something like this:
public void onMessage(Message message, Session session) throws JMSException {
try {
String msgText = ((TextMessage) message).getText();
// Processing occurs
// Web service is called
} catch (JMSException jmse) {
// log error
session.rollback(); // Question about this line
} catch (InvalidMessageException ime) {
// log error
// session is NOT rolled back, proceed to next message
} catch (SocketTimeoutException | AnyOtherRecoverableException excp) {
// log error
session.rollback();
}
}
In order to preserve ordering (sequencing), you have to roll back the message, if there are any exceptions because of the JMS provider (MQ server) failures.
Also please find the below text from oracle doc on getText() method:
TextMessage getText() method Throws:
JMSException - if the JMS provider fails to get the text due to some internal error

Resources