Java Http Client Request with Defined Timeout

Java HTTP Client Request with defined timeout

import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

...

// set the connection timeout value to 30 seconds (30000 milliseconds)
final HttpParams httpParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParams, 30000);
client = new DefaultHttpClient(httpParams);

Java HTTP Client request set timeout

Apache's HttpClient has two separate timeouts: a timeout for how long to wait to establish a TCP connection, and a separate timeout for how long to wait for a subsequent byte of data.

HttpConnectionParams.setConnectionTimeout() is used for establishing a TCP connection, whereas HttpConnectionParams.setSoTimeout() is used while waiting for a subsequent byte of data.

// Creating default HttpClient
HttpClient httpClient = new DefaultHttpClient();
final HttpParams httpParams = httpClient.getParams();

// Setting timeouts
HttpConnectionParams.setConnectionTimeout(httpParams, 5000);
HttpConnectionParams.setSoTimeout(httpParams, 30000);

// Rest of your code
final HttpPost httppost = new HttpPost(address);
httppost.setHeader("Accept", "text/xml");
httppost.setHeader("Content-type", "application/xml; charset=UTF-8");
httppost.setEntity(new StringEntity(body));
final HttpResponse response = httpclient.execute(httppost);
final HttpEntity entity = response.getEntity();

How to set socket timeout in Java HTTP Client

You can specify it at the HttpRequest.Builder level via the timeout method:

HttpClient httpClient = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(5))
.build();

HttpRequest httpRequest = HttpRequest.newBuilder()
.uri(URI.create("..."))
.timeout(Duration.ofSeconds(5)) //this
.build();

httpClient.send(httpRequest, HttpResponse.BodyHandlers.ofString());

If you've got connected successfully but not able to receive a response at the desired amount of time, java.net.http.HttpTimeoutException: request timed out will be thrown (in contrast with java.net.http.HttpConnectTimeoutException: HTTP connect timed out which will be thrown if you don't get a successful connection).

Using Apache HttpClient how to set the TIMEOUT on a request and response

The exceptions you'll see will be ConnectTimeoutException and SocketTimeoutException. The actual timeout values you use should be the maximum time your application is willing to wait. One important note about the read timeout is that it corresponds to the timeout on a socket read. So it's not the time allowed for the full response to arrive, but rather the time given to a single socket read. So if there are 4 socket reads, each taking 9 seconds, your total read time is 9 * 4 = 36 seconds.

If you want to specify a total time for the response to arrive (including connect and total read time), you can wrap the call in a thread and use a thread timeout for that. For example, I usually do something like this:

Future<T> future = null;
future = pool.submit(new Callable<T>() {
public T call() {
return executeImpl(url);
}
});

try {
return future.get(10, TimeUnit.SECONDS);
}
catch (InterruptedException e) {
log.warn("task interrupted", name);
}
catch (ExecutionException e) {
log.error(name + " execution exception", e);
}
catch (TimeoutException e) {
log.debug("future timed out", name);
}

Some assumptions made in the code above are: 1) this is in a function with a url parameter, 2) it's in a class with a name variable, 3) log is a log4j instance, and 4) pool is a some thread pool executor. Note that even if you use a thread timeout, you should also specify a connect and socket timeout on the HttpClient, so that slow requests don't eat up the resources in the thread pool. Also note that I use a thread pool because typically I use this in a web service so the thread pool is shared across a bunch of tomcat threads. You're environment may be different, and you may prefer to simply spawn a new thread for each call.

Also, I've usually see the timeouts set via member functions of the params, like this:

params.setConnectionTimeout(10000);
params.setSoTimeout(10000);

But perhaps your syntax works as well (not sure).

Java net HttpClient: React to timeout in async call

Depending on what you are trying to do, there are at least three methods that you could use to take action when an exception occurs:

  1. CompletableFuture.exceptionally
  2. CompletableFuture.whenComplete
  3. CompletableFuture.handle
  • 1 allows you to return a result of the same type when an exception occurs
  • 2 allows you to trigger some action - and doesn't change the completion
    result or exception.
  • 3 allows you to trigger some action, and change the type of the completion
    result or exception

By far the easiest would be to use 2. Something like:

client.sendAsync(request, HttpResponse.BodyHandlers.ofInputStream())
.whenComplete((r,x) -> {
if (x instanceof HttpTimeoutException) {
// do something
}
});

HttpClient request succeeds with timeout defined, but hangs without

I found the answer! Turns out HttpClient only allows a certain number of connections at a time. According to my code, the default maximum connections is 2. I needed to close each connection after they were complete and the upload ran fine.

Fixed code adds request connection release.

private void uploadParts(String assetId) throws IOException {
//set up post request
HttpClient client = HttpClientBuilder.create().build();

String url = "";

//prepare video
File video = new File("files/video.mp4");
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(video));

int partMaxSize = 1024 * 1024 * 5;
byte[] buffer = new byte[partMaxSize];
double fileSize = video.length();
System.out.println(fileSize);
System.out.println(fileSize / partMaxSize);
int parts = (int) Math.ceil(fileSize / partMaxSize);
System.out.println(parts);

for(int i = 1; i < parts+1; i++) {
String partNumber = i + "";
System.out.println("part: " + partNumber);
int partSize = (int) (i < parts ? partMaxSize : fileSize);
fileSize -= partSize;
int tmp = 0;
tmp = bis.read(buffer);
url = String.format("https://www.site.com/upload/multipart/%s/%s", assetId, partNumber);

final HttpPut request = new HttpPut(url);
request.addHeader("Authorization", "Bearer " + accessToken);
request.addHeader("Content-Type", "application/octet-stream");
request.setEntity(new ByteArrayEntity(buffer));

//Magical code start
int hardTimeout = 5; // seconds
TimerTask task = new TimerTask() {
@Override
public void run() {
if (request != null) {
request.abort();
}
}
};
new Timer(true).schedule(task, hardTimeout * 1000);
//Magical code end

HttpResponse response = client.execute(request);
request.releaseConnection();
System.out.println(response.getStatusLine().getReasonPhrase());
}
bis.close();
}

The timer was working because it was closing my old connections after 10 seconds. Thank you for your input, guys.



Related Topics



Leave a reply



Submit