5

All,

I am trying to decide whether to use NodeJS or Java for my application. I will be communicating with CouchDB over HTTP and would like an asynchronous non-blocking design where my application thread can process additional requests while it waits on the query response from CouchDB.

I would prefer to use Java and I have been looking at AsyncHttpClient for a few days as a potential solution. However, I am having some trouble understanding the library and think I may have a fundamental misunderstanding of something.

I posted a gist here: https://gist.github.com/conorgil/5505603

I would expect this gist to print out "Request X sent!" AND "Response X: something" for each request. However, it appears that the HTTP call is not made (and thus, the handler not executed) until each Future calls get(). Uncommenting line 23 f.get() makes the code work as expected, but the call to Future#get() is blocking, correct? Is there a way to just provide a callback function that gets executed once the HTTP response is fully retrieved without blocking?

Something like the following: 1) request comes in on main thread 2) async, non-blocking HTTP call is made to CouchDB. A completion handler is registered to process the response from CouchDB 3) the main thread is now free to process the next request 4) HTTP response from CouchDB arrives at some point and the registered handler is called to perform some business logic 5) main thread continues just processing requests (for requests that do not need to hit CouchDB, they can be responded to very quickly)

Am I fundamentally misunderstanding something here? Is it possible to do this type of thing in Java? Is AsyncHttpClient the answer? This question is related, but not sure if things have changed since 2011 (Perform Async Connect with Java AsyncHttpClient Library?)

Since NodeJS runs an event loop, this non-blocking, async behavior is standard. You would just register a callback function to handle the DB response when it was received and the event loop would just process other things in the meantime.

Any and all advice is appreciated.

Thanks, Conor

Community
  • 1
  • 1
conorgil
  • 355
  • 2
  • 13
  • Yes it is. Have a look at vert.x – Adam Gent May 06 '13 at 12:23
  • node.js is quite decent as a lightweight reverse proxy/gateway with minor app logic with couchdb simply because of couch's http interface and node's easy async http baked in. java is more performative for heavy app logic. – Gabe Rainbow Dec 05 '15 at 00:02

2 Answers2

3

The main purpose of AsyncHttpClient is non-blocking HTTP and I have successfully used it to that effect. For example, I ran this simplified version of your code:

public class MyAsyncHttpClientTest {
  public static void main(String[] args) throws Exception {
    AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
    for (int i = 0; i < 10; i++) {
      asyncHttpClient.prepareGet("http://www.google.com")
        .execute(new CompletionHandler(i));
      System.out.println(String.format("Request %d sent! ", i));
      System.out.flush();
    }
  }
  static class CompletionHandler extends AsyncCompletionHandler<Void> {
    private final int reqNumber;
    public CompletionHandler(int reqNumber) { this.reqNumber = reqNumber; }
    @Override public Void onCompleted(Response response) throws Exception {
      System.out.println(String.format("Response %d: %s", reqNumber,
          response.getResponseBody()));
      return null;
    }
  }
}

Notice no futures are involved. It produces the following output, just as one should expect:

Request 0 sent! 
Request 1 sent! 
Request 2 sent! 
Request 3 sent! 
Request 4 sent! 
Request 5 sent! 
Request 6 sent! 
Request 7 sent! 
Request 8 sent! 
Request 9 sent! 
Response 1: <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="http://www.google.hr/">here</A>.
</BODY></HTML>

Response 0: <HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>302 Moved</TITLE></HEAD><BODY>
<H1>302 Moved</H1>
The document has moved
<A HREF="http://www.google.hr/">here</A>.
</BODY></HTML>

...

The only trouble is, the process is left hanging because there is no code that shuts down the client, but that's a separate story.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • 1) AsyncCompletionHandler doc says that T Value that will be returned by the associated Future so even if you dont see futures, they are involved 2) I dont think you re demoing the non-blocking part here. you just showed that it is actually async. For non-blocking, you need to show that the ahc-thread that fired the request is not always the same as the one that processes the response. Non-blocking threads should fire the request and get back available in the pool instead of waiting for the response – stelios.anastasakis Jul 17 '20 at 23:17
  • 1
    `you need to show that the ahc-thread that fired the request is not always the same as the one that processes the response` -- one thread could fire the request, block for the raw response, and then let another thread process it, so it would again prove nothing. The ultimate proof here would be firing off way more requests than there are threads, but this answer isn't really about that level of mistrust in the AHC. – Marko Topolnik Jul 18 '20 at 06:49
  • As for the comment on futures, that's more of a nitpick, the shown code doesn't _use_ any futures. – Marko Topolnik Jul 18 '20 at 06:54
0

In case you can enhance your DB http server to support Async request then I will suggest to do so.

Generally Http Async requests are implemented using REQUEST SUBMIT->REQUEST ACCEPTED-> JOB POLLING -> JOB RESPONSE.

Asyn request are implemented using POST/PUT where you submit a request and you get 202 Accepted along with a polling URL in HTTP header to get the result asynchronously. Now you can poll this to get the result, if result is available you should get 200 OK with some result as xml/json/text output otherwise you may get error HTTP code such as 503 Service Unavailable.

Juned Ahsan
  • 67,789
  • 12
  • 98
  • 136