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.
Related
I want to make an asynchronous rest call for which I'm using spring webclient and getting back a Mono. I'm also doing some database calls in parallel but it can't be done reactively due to some reason.
Map<String, Object> models = new HashMap<>();
Mono<User> users = this.webClient...;
users.map(resp -> new UserState(userRequest, resp))
.subscribe(response -> {
models.put("userState", response);
});
Iterable<Product> messages = this.productRepository.findAll();
models.put("products", messages);
//Wait for users.subscribe to finish <<<<<<<<<<<<<HERE
return new ModelAndView("messages/list", models);
How do I wait for subscribe to finish before returning ModelAndView. This would have been easy if I was using a Future where I can do get() whenever I want.
You can wrap the blocking call in a Mono executed on a separate scheduler, zip it with the Mono containing UserState data and transform their combination into a Mono<ModelAndView> (which can be returned from Spring controller methods). The calls will be executed in parallel, results will be combined when both calls are completed.
You can define a single bounded scheduler per application specifically for blocking calls and provide it as a constructor argument to any class that makes blocking calls.
The code will look as follows:
#Configuration
class SchedulersConfig {
#Bean
Scheduler parallelScheduler(#Value("${blocking-thread-pool-size}") int threadsCount) {
return Schedulers.parallel(threadsCount);
}
}
#RestController
class Controller {
final Scheduler parallelScheduler;
...
Mono<User> userResponse = // webClient...
Mono<Iterable<Product>> productsResponse = Mono.fromSupplier(productRepository::findAll)
.subscribeOn(parallelScheduler);
return Mono.zip(userResponse, productsResponse, (user, products) ->
new ModelAndView("messages/list",
ImmutableMap.of(
"userState", new UserState(userRequest, user),
"products", products
))
);
}
Update based on the comment:
If you just need to execute HTTP call asynchronously and then join it with the database results you can do the following
Map<String, Object> models = new HashMap<>();
Mono<User> userMono = webClient...;
CompletableFuture<User> userFuture = userMono.toFuture();
Iterable<Product> messages = productRepository.findAll();
User user = userFuture.join();
models.put("products", messages);
models.put("userState", new UserState(userRequest, user));
return new ModelAndView("messages/list", models);
I am getting below error when I try to use #Async annotation.
java.lang.IllegalStateException: No thread-bound request found: Are you referring to request attributes outside of an actual web request, or processing a request outside of the originally receiving thread? If you are actually operating within a web request and still receive this message, your code is probably running outside of DispatcherServlet/DispatcherPortlet: In this case, use RequestContextListener or RequestContextFilter to expose the current request.
Code:
#Async
#Override
#Transactional
public void triggerEmailCommunication(List<String> eventCode, Integer authorizationId, Integer claimId,
boolean callMethod) {
Map<String, Object> emailBody = new HashMap<>();
try {
if (callMethod) {
LOGGER.info("Communication async flow triggerEmailCommunication method starts.");
emailBody = emailBodyObject(authorizationId, claimId, eventCode);
}
private Map<String, Object> emailBodyObject(Integer authorizationId, Integer claimId, List<String> eventCode)
throws CareBusinessServiceException {
LOGGER.info("EmailBodyObject method starts.");
Map<String, Object> emailBody = new HashMap<String, Object>();
EmailClaimDetailsVO emailClaimDetails = new EmailClaimDetailsVO();
ClaimAuthorizationVO claimAuthVO = new ClaimAuthorizationVO();
Claim claim = new Claim();
Authorization authorization = new Authorization();
List<String> rejectReasonList = new ArrayList<>();
Provider provider = new Provider();
String providerName = null;
String claimIntimationNbr = null;
String authorizationNbr = null;
SimpleDateFormat formatter = new SimpleDateFormat(AmhiConstants.DATE_FORMAT_DD_MM_YYYY);
try {
Integer claimIntimationId = null;
if (null != claimId) {
claim = enableBusinessService.retrieveClaimDetails(claimId);
} catch(Exception e) {
}
}
DAO Layer
#Override
public Claim retrieveClaimIdRecord(Integer claimId) {
CriteriaBuilder builder = manager.getCriteriaBuilder();
CriteriaQuery<Claim> criteriaQuery = builder.createQuery(Claim.class);
Root<Claim> root = criteriaQuery.from(Claim.class);
ArrayList<Predicate> conditions = new ArrayList<>();
conditions.add(builder.equal(root.get(Claim_.claimId), claimId));
criteriaQuery.select(root).where(conditions.toArray(new Predicate[] {}));
javax.persistence.Query query = manager.createQuery(criteriaQuery);
List<Claim> claims = query.getResultList();
if(CollectionUtils.isNotEmpty(claims)){
return claims.get(0);
}
return new Claim();
}
The value is getting retrieved from DB. But I am getting above exception as mentioned.
In my case it happened when I created a bean at request level and tried to access it from another thread created using #Async annotation. The bean information was stored in the thread local of the original thread only.
Are you using something created and stored in the thread local of the base thread in the function or subsequent functions after #Async notification?
#Async creates another thread but doesn't copy the thread local of the original thread which causes the issue.
See this - https://jira.spring.io/browse/SPR-6873
Hi I'm using the spring RestTemplate for calling a REST API. The API can be very slow or even offline. My application is building the cache by sending thousands of requests one after the other. The responses can be very slow too, because they contains a lot of data.
I have already increased the Timeout to 120 seconds. My problem now it that the API can be offline and I get a org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool exception.
In the case when the API ist offline, the application should wait and try again until the API is online again.
Can I achieve this in RestTemplate out of the box without building exception-loops on my own?
Thanks!
I had same situation and done some googling found the solution. Giving answer in hope it help someone else. You can set max try and time interval for each try.
#Bean
public RetryTemplate retryTemplate() {
int maxAttempt = Integer.parseInt(env.getProperty("maxAttempt"));
int retryTimeInterval = Integer.parseInt(env.getProperty("retryTimeInterval"));
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
retryPolicy.setMaxAttempts(maxAttempt);
FixedBackOffPolicy backOffPolicy = new FixedBackOffPolicy();
backOffPolicy.setBackOffPeriod(retryTimeInterval); // 1.5 seconds
RetryTemplate template = new RetryTemplate();
template.setRetryPolicy(retryPolicy);
template.setBackOffPolicy(backOffPolicy);
return template;
}
And my rest service that i want to execute is below.
retryTemplate.execute(context -> {
System.out.println("inside retry method");
ResponseEntity<?> requestData = RestTemplateProvider.getInstance().postAsNewRequest(bundle, ServiceResponse.class, serivceURL,
CommonUtils.getHeader("APP_Name"));
_LOGGER.info("Response ..."+ requestData);
throw new IllegalStateException("Something went wrong");
});
You can also tackle this annotation-driven using Spring Retry. This way you will avoid to implement the template.
Add it to your pom.xml
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.1.2.RELEASE</version>
</dependency>
Enable it for your application/configuration
#SpringBootApplication
#EnableRetry
public class MyApplication {
//...
}
Guard methods that are in danger of failure with #Retryable
#Service
public class MyService {
#Retryable(maxAttempts=5, value = RuntimeException.class,
backoff = #Backoff(delay = 15000, multiplier = 2))
public List<String> doDangerousOperationWithExternalResource() {
// ...
}
}
Use Spring Retry project (https://dzone.com/articles/spring-retry-ways-integrate, https://github.com/spring-projects/spring-retry).
It is designed to solve problems like yours.
This approach saved my day.!!!Resilience saved my day.[Resilience retry][1]
RetryConfig config = RetryConfig.custom()
.maxAttempts(4)
.waitDuration(Duration.ofMillis(2000))
.failAfterMaxAttempts(true)
.build();
RetryRegistry registry = RetryRegistry.of(config);
HttpEntity<String> request =
new HttpEntity<>(body, headers);
Retry retry = registry.retry("notification-endpoint-"+System.currentTimeMillis());
AtomicReference<Integer> retries = new AtomicReference<>(0);
retry.getEventPublisher().onRetry(e -> {
log.info("Retrying here!!!. Count: {}", retries.updateAndGet(v -> v + 1));
}).onError(e->{
log.error("Failed to get to client.");
});
if(requestPojo.getMethod().equalsIgnoreCase("GET")) {
response = Retry.decorateCheckedSupplier(
retry,
() -> restTemplateConfig.restTemplate()
.exchange(url, HttpMethod.GET, request, String.class)).unchecked().get();
}
else if(requestPojo.getMethod().equalsIgnoreCase("POST")) {
response = Retry.decorateCheckedSupplier(
retry,
() -> restTemplateConfig.restTemplate()
.exchange(url, HttpMethod.POST, request, String.class)).unchecked().get();
}```
[1]: https://resilience4j.readme.io/docs/retry
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.
I am working on a Java/Spring web application that for each incoming request does the following:
fires off a number of requests to third party web servers,
retrieves the response from each,
parses each response into a list of JSON objects,
collates the lists of JSON objects into a single list and returns it.
I am creating a separate thread for each request sent to the third party web servers. I am using the Apache PoolingClientConnectionManager. Here is an outline of the code I am using:
public class Background {
static class CallableThread implements Callable<ArrayList<JSONObject>> {
private HttpClient httpClient;
private HttpGet httpGet;
public CallableThread(HttpClient httpClient, HttpGet httpGet) {
this.httpClient = httpClient;
this.httpGet = httpGet;
}
#Override
public ArrayList<JSONObject> call() throws Exception {
HttpResponse response = httpClient.execute(httpGet);
return parseResponse(response);
}
private ArrayList<JSONObject> parseResponse(HttpResponse response) {
ArrayList<JSONObject> list = null;
// details omitted
return list;
}
}
public ArrayList<JSONObject> getData(List<String> urlList, PoolingClientConnectionManager connManager) {
ArrayList<JSONObject> jsonObjectsList = null;
int numThreads = urlList.size();
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
List<Future<ArrayList<JSONObject>>> list = new ArrayList<Future<ArrayList<JSONObject>>>();
HttpClient httpClient = new DefaultHttpClient(connManager);
for (String url : urlList) {
HttpGet httpGet = new HttpGet(url);
CallableThread worker = new CallableThread(httpClient, httpGet);
Future<ArrayList<JSONObject>> submit = executor.submit(worker);
list.add(submit);
}
for (Future<ArrayList<JSONObject>> future : list) {
try {
if (future != null) {
if (jsonObjectsList == null) {
jsonObjectsList = future.get();
} else {
if (future.get() != null) {
jsonObjectsList.addAll(future.get());
}
}
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
executor.shutdown();
return jsonObjectsList;
}
}
This all works fine. My question is in relation to how well this code will scale as the traffic to my website increases? Is there a better way to implement this? For example, by implementing non-blocking I/O to reduce the number of threads being created. Are there libraries or frameworks that might help?
At the moment, I am using Java 6 and Spring Framework 3.1
Thanks in advance
I wouldn't recommend to implement this as a synchronous service. Do it asynchronously. Get your request, pool the callables, and return a resource location where the client can later request the result.
You've got to be pooling this callables in an executor. Poll the executor in a background process and make avalable the results in the location you returned at the first request. Doing it this way, it would be easier to control your available resuources, and deny cleanly a processing requests if there aren't any more resources available.
Non blocking IO won't reduce the number of threads, it just delegates the "job" to another thread, in order for the service thread not to be blocked and to be able to receive more requests.
use REST.
Receive a POST request, and answer with something like this:
HTTP/1.1 202 Accepted
Location: /result/to/consult/later
The client can then request the resutl at the given location. If the processing has not finished, then answer with:
HTTP/1.1 201 Created
If its done then return a HTTP/1.1 200 OK with the resulting JSON.