How to use RestTemplate efficiently with RequestFactory? - java

I am working on a project in which I need to make a HTTP URL call to my server which is running Restful Service which returns back the response as a JSON String. I am using RestTemplate here along with HttpComponentsClientHttpRequestFactory to execute an url.
I have setup a http request timeout (READ and CONNECTION time out) on my RestTemplate by using HttpComponentsClientHttpRequestFactory.
Below is my Interface:
public interface Client {
// for synchronous
public String getSyncData(String key, long timeout);
// for asynchronous
public String getAsyncData(String key, long timeout);
}
Below is my implementation of Client interface -
public class DataClient implements Client {
private final RestTemplate restTemplate = new RestTemplate();
private ExecutorService executor = Executors.newFixedThreadPool(10);
// for synchronous call
#Override
public String getSyncData(String key, long timeout) {
String response = null;
try {
Task task = new Task(key, restTemplate, timeout);
// direct call, implementing sync call as async + waiting is bad idea.
// It is meaningless and consumes one thread from the thread pool per a call.
response = task.call();
} catch (Exception ex) {
PotoLogging.logErrors(ex, DataErrorEnum.CLIENT_ERROR, key);
}
return response;
}
// for asynchronous call
#Override
public Future<String> getAsyncData(String key, long timeout) {
Future<String> future = null;
try {
Task task = new Task(key, restTemplate, timeout);
future = executor.submit(task);
} catch (Exception ex) {
PotoLogging.logErrors(ex, DataErrorEnum.CLIENT_ERROR, key);
}
return future;
}
}
And below is my simple Task class
class Task implements Callable<String> {
private RestTemplate restTemplate;
private String key;
private long timeout; // in milliseconds
public Task(String key, RestTemplate restTemplate, long timeout) {
this.key = key;
this.restTemplate = restTemplate;
this.timeout = timeout;
}
public String call() throws Exception {
String url = "some_url_created_by_using_key";
// does this looks right the way I am setting request factory?
// or is there any other effficient way to do this?
restTemplate.setRequestFactory(clientHttpRequestFactory());
String response = restTemplate.exchange(url, HttpMethod.GET, null, String.class);
return response;
}
private static ClientHttpRequestFactory clientHttpRequestFactory() {
// is it ok to create a new instance of HttpComponentsClientHttpRequestFactory everytime?
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setReadTimeout(timeout); // setting timeout as read timeout
factory.setConnectTimeout(timeout); // setting timeout as connect timeout
return factory;
}
}
Now my question is - Does the way I am using RestTemplate along with setRequestFactory in the call method of Task class everytime is efficient? Since RestTemplate is very heavy to be created so not sure whether I got it right.
And is it ok to create a new instance of HttpComponentsClientHttpRequestFactory everytime? Will it be expensive?
What is the right and efficient way to use RestTemplate if we need to setup Read and Connection timeout on it.
This library will be used like this -
String response = DataClientFactory.getInstance().getSyncData(keyData, 100);

From what I can tell, you're reusing the same RestTemplate object repeatedly, but each Task is performing this line: restTemplate.setRequestFactory(clientHttpRequestFactory());. This seems like it can have race conditions, e.g. one Task can set the RequestFactory that another Task will then accidentally use.
Otherwise, it seems like you're using RestTemplate correctly.
How often do your timeouts change? If you mostly use one or two timeouts, you can create one or two RestTemplates using the RequestFactory constructor with the pre-loaded timeout. If you're a stickler for efficiency, create a HashMap<Integer, RestTemplate> that caches a RestTemplate with a particular timeout each time a new timeout is requested.
Otherwise, looking at the code for RestTemplate's constructor, and for HttpComponentsClientHttpRequestFactory's constructor, they don't look exceptionally heavy, so calling them repeatedly probably won't be much of a bottleneck.

Related

POST API request timeout issue

I'm trying to make a POST API call to our external API via the API PROXY. I'm facing some timeout issues while making a API call. I used below restTemplate to make a API request. But at the same time I've implemented the retry for the template in case of any timeouts. I can avoid this issue by retrying that api request again.But I would like to find out the root cause for that to completely resolve the issue.Can anyone help me with this
StackTrace:
org.springframework.web.client.ResourceAccessException: I/O error on POST request for "https://localhost:8080/test": Operation timed out (Read failed); nested exception is java.net.SocketException: Operation timed out (Read failed)
private static final int HTTP_CLIENT_RETRY_COUNT = 3;
private static final int MAXIMUM_TOTAL_CONNECTION = 10;
private static final int MAXIMUM_CONNECTION_PER_ROUTE = 5;
private static final int CONNECTION_VALIDATE_AFTER_INACTIVITY_MS = 10 * 1000;
public static RestTemplate createRestTemplate(int connectionTimeoutMs, int readTimeoutMs, ObjectMapper objectMapper) {
HttpClientBuilder clientBuilder = HttpClients.custom();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
// Set the maximum number of total open connections.
connectionManager.setMaxTotal(MAXIMUM_TOTAL_CONNECTION);
// Set the maximum number of concurrent connections per route, which is 2 by default.
connectionManager.setDefaultMaxPerRoute(MAXIMUM_CONNECTION_PER_ROUTE);
connectionManager.setValidateAfterInactivity(CONNECTION_VALIDATE_AFTER_INACTIVITY_MS);
clientBuilder.setConnectionManager(connectionManager);
clientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(HTTP_CLIENT_RETRY_COUNT, true, new ArrayList<>()) {
#Override
public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
LOGGER.info("Retry request, execution count: {}, exception: {}", executionCount, exception);
return super.retryRequest(exception, executionCount, context);
}
});
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory(clientBuilder.build());
httpRequestFactory.setConnectTimeout(connectionTimeoutMs);
httpRequestFactory.setConnectionRequestTimeout(readTimeoutMs);
httpRequestFactory.setReadTimeout(readTimeoutMs);
RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
List<ClientHttpRequestInterceptor> interceptors = new ArrayList<ClientHttpRequestInterceptor>();
interceptors.add(new LoggingRequestInterceptor());
restTemplate.setInterceptors(interceptors);
restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(httpRequestFactory));
MappingJackson2HttpMessageConverter messageConverter = restTemplate.getMessageConverters().stream().filter(MappingJackson2HttpMessageConverter.class::isInstance)
.map(MappingJackson2HttpMessageConverter.class::cast).findFirst().orElseThrow(() -> new RuntimeException("MappingJackson2HttpMessageConverter not found"));
messageConverter.setObjectMapper(objectMapper);
restTemplate.getMessageConverters().stream().filter(StringHttpMessageConverter.class::isInstance).map(StringHttpMessageConverter.class::cast).forEach(a -> {
a.setWriteAcceptCharset(false);
a.setDefaultCharset(StandardCharsets.UTF_8);
});
return restTemplate;
}

Spring RestTemplate - async vs sync restTemplate

I wrote the following code to test the performance of both the sync RestTemplate and AsyncRestTemplate. I just ran it a few times manually on POSTMAN.
We are just passing 10 references into a GET call so that we can return 10 links:
RestTemplate - synchronous and returns in 2806ms:
ArrayList<String> references = new ArrayList<>();
ArrayList<String> links = new ArrayList<>();
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
for (int i = 0; i < 10; i++) {
ResponseEntity<String> resource = restTemplate.getForEntity(references.get(i), String.class);
links.add(resource.getBody().toString());
}
RestTemplate - asynchronous and returns in 2794ms:
//Creating a synchronizedList so that when the async resttemplate returns, there will be no concurrency issues
List<String> links = Collections.synchronizedList(new ArrayList<String>());
//CustomClientHttpRequestFactory just extends SimpleClientHttpRequestFactory but disables automatic redirects in SimpleClientHttpRequestFactory
CustomClientHttpRequestFactory customClientHttpRequestFactory = new CustomClientHttpRequestFactory();
//Setting the ThreadPoolTaskExecutor for the Async calls
org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor pool = new org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor();
pool.setCorePoolSize(5);
pool.setMaxPoolSize(10);
pool.setWaitForTasksToCompleteOnShutdown(true);
pool.initialize();
//Setting the TaskExecutor to the ThreadPoolTaskExecutor
customClientHttpRequestFactory.setTaskExecutor(pool);
ArrayList<String> references = new ArrayList<>();
ArrayList<String> links = new ArrayList<>();
AsyncRestTemplate asyncRestTemplate = new AsyncRestTemplate(customClientHttpRequestFactory);
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
for (int i = 0; i < 10; i++) {
Future<ResponseEntity<String>> resource = asyncRestTemplate.getForEntity(references.get(i), String.class);
ResponseEntity<String> entity = resource.get(); //this should start up 10 threads to get the links asynchronously
links.add(entity.getBody().toString());
}
In most cases, both methods actually return back the results with a very similar time, averaging 2800ms in both async and sync calls.
Am I doing something incorrect as I would have expected the async call to be much faster?
Nowadays, AsyncRestTemplate is #Deprecated in favor of WebClient. So nobody should use that class anymore!
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/reactive/function/client/WebClient.html
I would say that you're missing the real benefits of the AsyncRest here.
You should add callbacks to each requests you're sending so that the response will be processes only when available.
Indeed, the getForEntity method of an AsyncRestTemplate returns a ListenableFuture to which you can connect a callback task. See the official doc ListenableFuture for further information.
For example in your case it could be:
for (int i = 0; i < 10; i++) {
ListenableFuture<ResponseEntity<String>> response = asyncRestTemplate.getForEntity(references.get(i), String.class);
response.addCallback(new ListenableFutureCallback<ResponseEntity<String>>() {
#Override
public void onSuccess(ResponseEntity<String> result) {
// Do stuff onSuccess
links.add(result.getBody().toString());
}
#Override
public void onFailure(Throwable ex) {
log.warn("Error detected while submitting a REST request. Exception was {}", ex.getMessage());
}
});
}
The tricky thing with Java Future is that it's not composable and it's really easy to block.
In this case, calling future.get() makes your code block and wait until the response is back. In fact, this approach makes sequential calls and does not leverage the async nature of this RestTemplate implementation.
The simplest way to fix this is to separate it in two loops:
ArrayList<Future<ResponseEntity<String>>> futures = new ArrayList<>();
for (String url : references.get()) {
futures.add(asyncRestTemplate.getForEntity(url, String.class)); //start up to 10 requests in parallel, depending on your pool
}
for (Future<ResponseEntity<String>> future : futures) {
ResponseEntity<String> entity = future.get(); // blocking on the first request
links.add(entity.getBody().toString());
}
Obviously there are more elegant solutions, especially if using JDK8 streams, lambdas and ListenableFuture/CompletableFuture or composition libraries.

How do I kill Apache HttpClient I/O Dispatcher threads after main() exits?

I'm using Spring's AsyncRestTemplate backed by Apache HttpAsyncClient. My configuration is based on this blog entry.
When running my asynchronous code in JUnit, everything exits cleanly. I suspect this is because JUnit kills all running threads when the test method exits.
#Test
public void loadFirstSISOfferingFromFactory() throws Exception {
CourseOfferingService factoryCourseService = ValenceServiceFactory.getCourseOfferingService();
BlockingQueue<CourseOffering> queue = factoryCourseService.getAllCourseOfferings();
CourseOffering course = queue.take();
LOG.info( course.toString() );
}
When I run this same test in a main() method (as it will be when deployed), the I/O dispatcher threads fail to exit.
public static void main( final String args[] ) throws Exception {
CourseOfferingService courseService = ValenceServiceFactory.getCourseOfferingService();
BlockingQueue<CourseOffering> queue = courseService.getAllCourseOfferings();
CourseOffering course = queue.take();
System.out.println( course.toString() );
}
The code works correctly – that is, it connects to the REST API I expect, loads the correct data, executes the callback method, and populates the queue. The ValenceServiceFactory generates Spring beans (I'm using this so non-Spring enabled projects to access my services). However, when all the connections are idle and the main thread has completed, the I/O dispatcher threads live on.
Here's my Spring Configuration:
#Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate( new HttpComponentsClientHttpRequestFactory() );
restTemplate.setErrorHandler( new DefaultResponseErrorHandler() {
#Override
public void handleError( ClientHttpResponse response ) throws IOException {
// Do nothing when error is found.
// Hopefully the status code will be passed to the ResponseEntity
}
} );
return restTemplate;
}
#Bean
public AsyncRestTemplate asyncRestTemplate() throws IOReactorException {
// Configure Apache Http Client
PoolingNHttpClientConnectionManager connectionManager = new PoolingNHttpClientConnectionManager( //
new DefaultConnectingIOReactor( IOReactorConfig.DEFAULT ) );
connectionManager.setMaxTotal( 1000 ); //Total Connections
connectionManager.setDefaultMaxPerRoute( 900 ); //Max connections per host
RequestConfig config = RequestConfig.custom() //
.setConnectTimeout( 60 * 1000 ) // milliseconds
.build();
CloseableHttpAsyncClient httpclient = HttpAsyncClientBuilder.create() //
.setConnectionManager( connectionManager ) //
.setDefaultRequestConfig( config ) //
.build();
AsyncRestTemplate restTemplate = new AsyncRestTemplate( //
new HttpComponentsAsyncClientHttpRequestFactory( httpclient ), restTemplate() );
return restTemplate;
}
I suppose dropping a System.exit(0) at the end of the main method, but if there's a running background process I want to complete, it'll be killed immediately, rather than waiting to complete.
Essentially, I'm looking for an equivalent of java.util.concurrent.ExecutorService.shutdown() and .awaitTermination(), except for AsyncRestTemplate or HttpAsyncClient. In theory, a clean shutdown would be possible after each dispatcher thread has been idle a certain time.
Is that possible? Am I forced to use System.exit()?
Thanks in advance.

SimpleClientHttpRequestFactory vs HttpComponentsClientHttpRequestFactory for Http Request timeout with RestTemplate?

I am working on a project in which I need to make a HTTP URL call to my server which is running Restful Service which returns back the response as a JSON String.
Below is my main code which is using the future and callables:
public class TimeoutThreadExample {
private ExecutorService executor = Executors.newFixedThreadPool(10);
private RestTemplate restTemplate = new RestTemplate();
public String getData() {
Future<String> future = executor.submit(new Task(restTemplate));
String response = null;
try {
response = future.get(500, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return response;
}
}
Below is my Task class which implements the Callable interface and uses the RestTemplate:
class Task implements Callable<String> {
private RestTemplate restTemplate;
public Task(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public String call() throws Exception {
String url = "some_url";
String response = restTemplate.getForObject(url, String.class);
return response;
}
}
Problem Statement:
As you can see above, I am using default way of executing the URL using RestTemplate which doesn't use any Http Request timeout so that means internally it is using -1 as the read and connection timeout.
Now what I am looking to do is, I want to set up Http Request timeout using RestTemplate in my above code efficiently. And I am not sure which class I need to use for that, I can see HttpComponentsClientHttpRequestFactory and SimpleClientHttpRequestFactory so not sure which one I need to use?
Any simple example basis on my above code will help me understand better on how to set the Http Request timeout using RestTemplate.
And also does my Http Request timeout value should be less than future timeout value?
HttpComponentsClientHttpRequestFactory vs SimpleClientHttpRequestFactory. Which one to use?
Does my Http Request timeout value should be less than future timeout value?
By default RestTemplate uses SimpleClientHttpRequestFactory which depends on default configuration of HttpURLConnection.
You can configure them by using below attributes:
-Dsun.net.client.defaultConnectTimeout=TimeoutInMiliSec
-Dsun.net.client.defaultReadTimeout=TimeoutInMiliSec
If you want to use HttpComponentsClientHttpRequestFactory - it has a connection pooling configuration which SimpleClientHttpRequestFactory does not have.
A sample code for using HttpComponentsClientHttpRequestFactory:
public class TimeoutThreadExample {
private ExecutorService executor = Executors.newFixedThreadPool(10);
private static final RestTemplate restTemplate = createRestTemplate();
private static RestTemplate createRestTemplate(){
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setReadTimeout(READ_TIME_OUT);
requestFactory.setConnectTimeout(CONNECTION_TIME_OUT);
return new RestTemplate(requestFactory);
}
public String getData() {
Future<String> future = executor.submit(new Task(restTemplate));
String response = null;
try {
response = future.get(500, TimeUnit.MILLISECONDS);
} catch (TimeoutException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return response;
}
}
SimpleClientHttpRequestFactory uses the standard JDK's HTTP library, and hence does not support methods like HttpMethod.PATCH. So it's better to use HttpComponentsClientHttpRequestFactory now than change it later when you have to.

how to commit or flush the rest response in the middle of process

I'm new to both java and jersey. Now I want to use the jersey to realize a REST services with extra processing after sending the response (specifically, sleep a fix amount of seconds and then fire a different REST request in the same servlet context, so it's unlike a REST proxy). I had googled for a while but all seems take it for granted that implicitly flushing the response at the end of method. Here are the current codes with JAXB enabled I'm struggling to work on.
#Path("/chat")
public class LoadSimulator {
#Context private UriInfo uriInfo;
#Path("/outbound/{senderAddress}/requests")
#POST
#Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
#Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Response createOutboundSMSMessage(OutboundSMSMessageRequest inSmsReq, #PathParam("senderAddress") String senderAddress) throws JAXBException {
String requestId = UUID.randomUUID().toString();
URI uri = uriInfo.getAbsolutePathBuilder().path(requestId).build();
ObjectFactory factory = new ObjectFactory();
ResourceReference resourceReference = new ResourceReference();
resourceReference.setResourceURL(uri.toString());
JAXBElement<ResourceReference> inSmsResponse = factory.createResourceReference(resourceReference);
return Response.created(uri).entity(inSmsResponse).build();
//// want to flush or commit the response explicitly like:
// out.flush();
// out.close();
//// Then sleep for a few second and fire a new REST request
// sleep(5);
// ....
// ClientConfig config = new DefaultClientConfig();
// String response = r.path("translate").queryParams(params).get(String.class);
}
}
If you could do what you're trying to do, you would exhaust the resources on your server because every request would take X seconds and you have a finite amount of threads available before the box cries uncle.
Without commenting on why you'd want to do this; If you used the #Singleton annotation for your LoadSimulator you could set up a thread that listens on a (concurrent) queue in #PostConstruct public void init() - that gets called when your servlet starts up.
#Singleton
#Path("/chat")
public class LoadSimulator {
private Thread restCaller;
private ConcurrentLinkedQueue<MyInfo> queue = new ConcurrentLinkedQueue<MyInfo>();
...
#PostConstruct public void init()
{
restCaller = new Thread(new MyRunnable(queue));
restCaller.start();
}
...
Then in your REST call, you'd put whatever information is needed to make the second REST call on that queue, and have the aforementioned thread pulling it off and making queries.

Categories

Resources