2015-05-29 21 views
6

L'utilizzo del AsyncHttpClient con il provider Netty impedirà il termine del programma principale quando si esegue una richiesta asincrona. Per esempio, il seguente programma termina dopo la println, o meno, a seconda che il provider è JDKAsyncHttpProvider o NettyAsyncHttpProvider:Come chiudere AsyncHttpClient con Netty per una richiesta Http asincrona?

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()); 
    } 
} 

Chi l'AsynHttpClient gli stati di documentazione:

AHC è un livello di astrazione che può funzionare in cima al nudo JDK, Netty e Grizzly. Nota che l'implementazione di JDK è molto limitata e dovresti VERAMENTE usare gli altri provider reali.

Per utilizzare AsyncHttpClient con Netty, è sufficiente includere la libreria corrispondente nel percorso di classe java. Quindi, possiamo eseguire la precedente Program con una delle seguenti configurazioni di percorso classe da utilizzare Netty, oppure no:

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

Che altro dovremmo fare per usare correttamente il provider di Netty? Ad esempio, sto chiudendo lo AsyncHttpClient in AsyncCompletionHandler. È corretto?

Esiste una configurazione per modificare il comportamento osservato?

+0

non è 'AsyncHttpClient' thread-safe? Non crearne uno nuovo su ogni invocazione di metodo. –

+0

se provi a chiudere il client molto più tardi, ad es. dopo 'thenAccept', l'applicazione si interrompe? – ZhongYu

+0

N. Chiusura, o non, asyncHttpClient non ha alcuna influenza sul comportamento risultante. –

risposta

4

Utilizzando il provider netty e passando attraverso di esso nel debugger, vedo che chiamare asyncHttpClient.close() all'interno del callback fa sì che NioSocketChannelFactory.releaseExternalResources() fallisca quando tenta di eseguire il suo arresto. Viene generata un'eccezione, e questo probabilmente fa sì che il thread non daemon rimanga e impedisca l'uscita da VM. L'eccezione generata viene registrata in WARN, quindi probabilmente non la vedrai (se aggiungi slf4j-log4j12-1.7.7.jar al classpath dovresti vederlo). Quindi non è possibile chiamare close() nella richiamata (e non è necessario chiuderla dopo ogni esecuzione di richiesta in ogni caso).

Ecco la traccia:

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)