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?
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With