11

I have a high volume java application in which I have to send http posts to another server. Currently I'm using org.apache.commons.httpclient library:

private static void sendData(String data) {
HttpClient httpclient = new HttpClient();
StringRequestEntity requestEntity;
try {
    requestEntity = new StringRequestEntity(data, "application/json", "UTF-8");
    String address = "http://<my host>/events/"
    PostMethod postMethod = new PostMethod(address);
    postMethod.setRequestEntity(requestEntity);

    httpclient.executeMethod(postMethod);

} catch (Exception e) {
    LOG.error("Failed to send data ", e);

}
}

This means I'm sending my http requests synchronously, which doesn't fit my multithreaded high volume app. So I would like to change those calls to asynchronous non-blocking http calls.

I was going through number of options such as apache async client and xsocket but was not able to make it work.

Tried ning:

private static void sendEventToGrpahiteAsync(String event) {
LOG.info("\n" + "sendEventToGrpahiteAsync");
try (AsyncHttpClient asyncHttpClient = new AsyncHttpClient()) {
    BoundRequestBuilder post = asyncHttpClient.preparePost();
    post.addHeader("Content-Type", "application/json");
    post.setBodyEncoding("UTF-8");
    post.setBody(event);
    post.execute(new HttpRequestCompletionHandler());
} catch (Exception e) {
    LOG.error("Failed to sending event", e);
}
}

I tried Apache HttpAsyncClient:

private static void sendEventToGrpahiteAsync(String event) {
LOG.info("\n" + "sendEventToGrpahiteAsync");
try (CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault()) {
    httpclient.start();
    HttpPost request = new HttpPost(addr);
    StringEntity entity = new StringEntity(event, ContentType.create("application/json", Consts.UTF_8));
    request.setEntity(entity);
    httpclient.execute(request, null);
} catch (Exception e) {
    LOG.error("Failed to sending event", e);
}
}

I tried xsocket:

private static void sendEventToGrpahiteAsync2(String event) {
LOG.info("\n" + "sendEventToGrpahiteAsync");
try (INonBlockingConnection con = new NonBlockingConnection(<SERVER_IP>, 80);
    IHttpClientEndpoint httpClientConnection = new HttpClientConnection(con)) {
    IHttpResponseHandler responseHandler = new MyResponseHandler();
    IHttpRequest request = new PostRequest(url_address, "application/json", Consts.UTF_8.toString(), event);
    request.setTransferEncoding(Consts.UTF_8.toString());
    httpClientConnection.send(request, responseHandler);
} catch (Exception e) {
    LOG.error("Failed to sending event", e);
}
}

I get no exceptions but the post doesn't get to the target as well. To be clear, the target is a graphite server so once a post arrives it is clearly seen in a graph. The synchronous posts works well, I can see the result on the graph, but none of the asynchronous posts shows on my destination graph.

What am I missing?

Thanks

forhas
  • 11,551
  • 21
  • 77
  • 111

2 Answers2

4

Got it.

All the libraries I'n using are implemented using an extra IO thread, so my process probably ends before a full handshake.

Once I added Thread.sleep(2000) after the http calls things worked just fine. So for a web app (which is my case) my suggested implementations are just fine (but for a java process you might consider NickJ's answer).

forhas
  • 11,551
  • 21
  • 77
  • 111
  • 2
    If you are using an extra IO Thread you are still harming the overall thread pool right ? at the end of the day you are using 1 thread more to handle the call back, isn't ? – Diego Ramos Jul 13 '19 at 18:21
-2

You could use the Java Executor framework:

First, create a Callable to do your work:

public class MyCallable implements Callable<MyResult> {
  @Override
  public MyResult call() throws Exception {
    //do stuff
    return result;
  }
} 

Get an Exectutor which will run your Callable. There are various way to get one, here's one example:

ExecutorService executor = Executors.newFixedThreadPool(NTHREDS);

Finally, run it:

MyCallable callable = new MyCallable();
Future<MyResult> futureResult = executor.submit(callable);

Getting the result:

boolean resultReady = futureResult.isDone(); //is the result ready yet?
Result r = futureResult.get(); //wait for result and return it

try {
  Result r = futureResult.get(10, TimeUnit.SECONDS); //wait max. 10 seconds for result
} catch (TimeOutException e) {
  //result still not ready after waiting 10 seconds
}
NickJ
  • 9,380
  • 9
  • 51
  • 74
  • Nice, but I rather use a library that does this for me, unless there isn't any, but as far as I see there are a few. – forhas Jan 09 '14 at 13:30
  • 9
    doesn't this simply fire a thread per request instead of true non-blocking i/o? – necromancer Aug 04 '14 at 09:22
  • 7
    This is no different then blocking on the calling thread. You should use a NIO client to do proper non blocking requests. – HaxElit Aug 17 '15 at 19:29
  • 1
    This is nowhere related to what OP has asked. @forhas HttpClient is multithreaded so it could fit your use case. However I think what you are looking is a higher throughput client, so using a NIO based non blocking client makes sense. You should clarify this in your question. Also keep in mind that NIO clients will only help if you need to handle more concurrent connections, otherwise, the regular BIO client should be good. – Ravi Sanwal Aug 21 '17 at 19:42