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.
Related
I'm new to spring boot and I'm trying to create a streaming API. But when I change the content of value it doesn't get noticed by the Server Side Events emitter.
#RestController
public class SseController {
ExecutorService executor = Executors.newSingleThreadExecutor();
RestTemplate restTemplate = new RestTemplate();
String result;
//This method only returns a single value. But I want it to return value after every 5 second.
#GetMapping("/emitter")
public SseEmitter eventEmitter() {
SseEmitter emitter = new SseEmitter();
executor.execute(() -> {
try {
//I'm Sending Value To the client Using this method
emitter.send(result);
} catch (Exception e) {
emitter.completeWithError(e);
} finally {
emitter.complete();
}
});
executor.shutdown();
return emitter;
}
//I'm updating value here.
#Scheduled(fixedRate = 5000)
private void fetchData() {
result = restTemplate.getForObject("https://api.wazirx.com/api/v2/tickers", String.class);
}
}
I have tried to use thread.sleep() method but after some time it gives me an error async time out.
I know that timeout is a property of client , but we need to send a response in 2 minutes from spring soap endpoint.
How to timeout in spring soap and send a default response within a specified time from soap producer app?
Container : Tomcat
#Endpoint
public class SOAPEndpoint {
private static final String NAMESPACE_URI = "http://spring.io/guides/gs-producing-web-service";
private Repository repository;
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "getData")
#ResponsePayload
public Response getCountry(#RequestPayload SampleRequest request) {
Response response = new Response();
response.setCountry(repository.retrieveData(request.getParam())); // this lines takes 5 minutes to respond
return response;
}
}
I wasn't able to find a configuration-based solution, but here are possible library-based solutions:
Some DBs lets you to set a query timeout, so if it's available for you, it seems like a good approach. If you will specify the DB you use, I will dig into it.
You can use the TimeLimiter of resilience4j:
#PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest")
#ResponsePayload
public GetCountryResponse getCountry(#RequestPayload GetCountryRequest request) {
GetCountryResponse response = new GetCountryResponse();
TimeLimiter timeLimiter = TimeLimiter.of(Duration.ofSeconds(1));
try {
Country country = timeLimiter.executeFutureSupplier(() ->
CompletableFuture.supplyAsync(() -> countryRepository.findCountry(request.getName())));
response.setCountry(country);
return response;
} catch (TimeoutException e) {
e.printStackTrace(); // handle timeout.
} catch (Exception e) {
e.printStackTrace(); // handle general error.
}
return null; // You may want to replace this.
}
The Producer code above is originated from - https://spring.io/guides/gs/producing-web-service/
and was tested against the Consumer - https://spring.io/guides/gs/consuming-web-service/
Here is my code.What I want to do is to test three kinds of exceptions.But I don't know how to mock local variable restTemplate.
my code:
private void setJobInstanceInfo(JobInstance jobInstance, String uri, String group, String jobName) {
RestTemplate restTemplate = new RestTemplate();
TypeReference<HashMap<String, Object>> type = new TypeReference<HashMap<String, Object>>() {
};
try {
String resultStr = restTemplate.getForObject(uri, String.class);
HashMap<String, Object> resultMap = JsonUtil.toEntity(resultStr, type);
setJobInstanceIdAndUri(jobInstance, resultMap);
} catch (RestClientException e) {
LOGGER.error("spark session {} has overdue, set state as unknown!\n {}", jobInstance.getSessionId(), e.getMessage());
setJobInstanceUnknownStatus(jobInstance);
} catch (IOException e) {
LOGGER.error("jobInstance jsonStr convert to map failed. {}", e.getMessage());
} catch (IllegalArgumentException e) {
LOGGER.warn("Livy status is illegal. {}", group, jobName, e.getMessage());
}
}
When call restTemplate.getForObject(uri, String.class),it always throws exception as below:
"I/O error on GET request for url: Connection refused: connect".
I know it's url problem.That's what I want to mock and return anything I expect.
So,can you give methods to test this three kinds of exception of RestClientException and IOException and IllegalArgumentException?
At first do not instantiate the RestTemplate in your methods! Let Spring create it for you, e.g. add this to a spring configuration
#Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
Then you can start writing a rest client test like described here:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-testing.html#boot-features-testing-spring-boot-applications-testing-autoconfigured-rest-client
I would like to cancel a REST request, if the response takes longer than 3 seconds, but I haven't managed to figure out how to do it.
So let's say I have a thread A:
#Override
public void run() {
RestTemplate restTemplate = new RestTemplate();
IsAliveMessage isAliveMessage = new IsAliveMessage(nodeInfo.getHostname(), nodeInfo.getPort());
IsAliveResponse isAliveResponse = restTemplate.postForObject(
"http://" + nodeInfo.getHostname() + ":" + nodeInfo.getPort() + "/node/isAlive",
isAliveMessage,
IsAliveResponse.class);
}
that makes a request and expects an answer from B:
#RequestMapping( value="/isAlive", method= RequestMethod.POST)
public IsAliveResponse isAlive() throws ConnectException {
try {
Thread.sleep(100000);
IsAliveResponse response = new IsAliveResponse("here here!" ,true);
return response;
} catch (Exception e) {
Thread.currentThread().interrupt();
}
}
B "sleeps" and doesn't answer, but A keeps waiting for that answer to come. How can I make A give up the waiting after a certain time span?
Thanks in advance
You can configure your RestTemplate to wait three seconds for response like this:
RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
private ClientHttpRequestFactory getClientHttpRequestFactory() {
int timeout = 3000;
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory =
new HttpComponentsClientHttpRequestFactory();
clientHttpRequestFactory.setConnectTimeout(timeout);
clientHttpRequestFactory.setReadTimeout(timeout);
return clientHttpRequestFactory;
}
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.