Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to close AsyncHttpClient with Netty for an asynchronous Http request?

Using the AsyncHttpClient with Netty provider will prevent the main program to terminate when we execute an asynchronous request. For instance, the following program terminates after the println, or not, depending on whether the provider is JDKAsyncHttpProvider or NettyAsyncHttpProvider:

public class Program {
    public static CompletableFuture<Response> getDataAsync(String uri) {
        final AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
        final CompletableFuture<Response> promise = new CompletableFuture<>();
        asyncHttpClient
            .prepareGet(uri)
            .execute(new AsyncCompletionHandler<Response>(){
                @Override
                public Response onCompleted(Response resp) throws Exception {
                    promise.complete(resp);
                    asyncHttpClient.close(); // ??? Is this correct ????
                    return resp;
                }
            });
        return promise;
    }

    public static void main(String [] args) throws Exception {
        final String uri = "…";
        System.out.println(getDataAsync(uri).get());
    }
}

About the AsynHttpClient the documentation states:

AHC is an abstraction layer that can work on top of the bare JDK, Netty and Grizzly. Note that the JDK implementation is very limited and you should REALLY use the other real providers.

To use AsyncHttpClient with Netty we just need to include the corresponding library in the java class path. So, we may run the previous Program with one of the following class path configurations to use Netty, or not:

  • -cp .;async-http-client-1.9.24.jar;netty-3.10.3.Final.jar;slf4j-api-1.7.12.jar will use NettyAsyncHttpProvider
  • -cp .;async-http-client-1.9.24.jar;slf4j-api-1.7.12.jar will use JDKAsyncHttpProvider

What else should we do to use Netty provider correctly? For instance, I am closing the AsyncHttpClient in AsyncCompletionHandler. Is that correct?

Is there any configuration to change the observed behavior?

like image 565
Miguel Gamboa Avatar asked May 29 '15 16:05

Miguel Gamboa


1 Answers

Using the netty provider and stepping through it in the debugger, I see that calling asyncHttpClient.close() inside the callback causes NioSocketChannelFactory.releaseExternalResources() to fail when it tries to do its shutdown. An exception is thrown, and this is likely causing the non daemon thread to remain, and keeping the vm from exiting. The exception thrown is logged at WARN, so you're probably not seeing it (if you add slf4j-log4j12-1.7.7.jar to you classpath you should see it). So you can't call close() in the call back (and you don't need to close it after every request execution anyhow).

Here's the trace:

 WARN [New I/O worker #1] (NettyAsyncHttpProvider.java:79) - Unexpected error on close
java.lang.IllegalStateException: Must not be called from a I/O-Thread to prevent deadlocks!
at org.jboss.netty.channel.socket.nio.AbstractNioSelector.shutdown(AbstractNioSelector.java:415)
at org.jboss.netty.channel.socket.nio.NioWorker.shutdown(NioWorker.java:36)
at org.jboss.netty.channel.socket.nio.AbstractNioWorkerPool.shutdown(AbstractNioWorkerPool.java:142)
at org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory.releaseExternalResources(NioClientSocketChannelFactory.java:225)
at com.ning.http.client.providers.netty.channel.ChannelManager.close(ChannelManager.java:355)
at com.ning.http.client.providers.netty.NettyAsyncHttpProvider.close(NettyAsyncHttpProvider.java:70)
at com.ning.http.client.AsyncHttpClient.close(AsyncHttpClient.java:336)
at com.cie.program.Program$1.onCompleted(Program.java:23)
like image 145
Alper Akture Avatar answered Nov 09 '22 23:11

Alper Akture