Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 490A5200C02 for ; Fri, 20 Jan 2017 16:54:34 +0100 (CET) Received: by cust-asf.ponee.io (Postfix) id 4780B160B39; Fri, 20 Jan 2017 15:54:34 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 467AE160B48 for ; Fri, 20 Jan 2017 16:54:33 +0100 (CET) Received: (qmail 23124 invoked by uid 500); 20 Jan 2017 15:54:32 -0000 Mailing-List: contact dev-help@hc.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "HttpComponents Project" Delivered-To: mailing list dev@hc.apache.org Received: (qmail 23113 invoked by uid 99); 20 Jan 2017 15:54:32 -0000 Received: from pnap-us-west-generic-nat.apache.org (HELO spamd4-us-west.apache.org) (209.188.14.142) by apache.org (qpsmtpd/0.29) with ESMTP; Fri, 20 Jan 2017 15:54:32 +0000 Received: from localhost (localhost [127.0.0.1]) by spamd4-us-west.apache.org (ASF Mail Server at spamd4-us-west.apache.org) with ESMTP id 0ECDDC0D33 for ; Fri, 20 Jan 2017 15:54:32 +0000 (UTC) X-Virus-Scanned: Debian amavisd-new at spamd4-us-west.apache.org X-Spam-Flag: NO X-Spam-Score: -1.198 X-Spam-Level: X-Spam-Status: No, score=-1.198 tagged_above=-999 required=6.31 tests=[KAM_ASCII_DIVIDERS=0.8, KAM_LAZY_DOMAIN_SECURITY=1, LOTS_OF_MONEY=0.001, RP_MATCHES_RCVD=-2.999] autolearn=disabled Received: from mx1-lw-eu.apache.org ([10.40.0.8]) by localhost (spamd4-us-west.apache.org [10.40.0.11]) (amavisd-new, port 10024) with ESMTP id mkPs7NabEtD3 for ; Fri, 20 Jan 2017 15:54:29 +0000 (UTC) Received: from mailrelay1-us-west.apache.org (mailrelay1-us-west.apache.org [209.188.14.139]) by mx1-lw-eu.apache.org (ASF Mail Server at mx1-lw-eu.apache.org) with ESMTP id 7F4795FC5F for ; Fri, 20 Jan 2017 15:54:28 +0000 (UTC) Received: from jira-lw-us.apache.org (unknown [207.244.88.139]) by mailrelay1-us-west.apache.org (ASF Mail Server at mailrelay1-us-west.apache.org) with ESMTP id 42FD3E026F for ; Fri, 20 Jan 2017 15:54:27 +0000 (UTC) Received: from jira-lw-us.apache.org (localhost [127.0.0.1]) by jira-lw-us.apache.org (ASF Mail Server at jira-lw-us.apache.org) with ESMTP id 97A352528A for ; Fri, 20 Jan 2017 15:54:26 +0000 (UTC) Date: Fri, 20 Jan 2017 15:54:26 +0000 (UTC) From: "Oleg Kalnichevski (JIRA)" To: dev@hc.apache.org Message-ID: In-Reply-To: References: Subject: [jira] [Commented] (HTTPASYNC-117) Blocking thread when executing a request in a FutureCallback MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 7bit X-JIRA-FingerPrint: 30527f35849b9dde25b450d4833f0394 archived-at: Fri, 20 Jan 2017 15:54:34 -0000 [ https://issues.apache.org/jira/browse/HTTPASYNC-117?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=15831992#comment-15831992 ] Oleg Kalnichevski commented on HTTPASYNC-117: --------------------------------------------- Michael HttpAsyncClient 4.x has not been designed to handle such use case. Generally one _ought_ to keep code executed in callbacks as light as possible given the same I/O dispatch thread has to handle I/O events of multiple connections. This especially implies avoidance of potentially blocking or time consuming operations in callbacks. So, one _ought_ not attempt to submit a new request directly from the result callback of another request. There is nothing I can about the problem other than suggesting to use an intermediate request queue managed by a dedicated thread for request submission and revisiting the problem in the course of 5.0 development. Oleg > Blocking thread when executing a request in a FutureCallback > ------------------------------------------------------------ > > Key: HTTPASYNC-117 > URL: https://issues.apache.org/jira/browse/HTTPASYNC-117 > Project: HttpComponents HttpAsyncClient > Issue Type: Bug > Affects Versions: 4.1.2 > Environment: Environment Oracle JDK 8u121 > Reporter: Michael Ernst > Priority: Critical > Attachments: blocking-thread-example-application.zip > > > When executing a request within a {{FutureCallback}} (inner request) the invoking thread is blocked. The inner request will not be executed and processing the request terminates after the write event. > If the inner request is executed in another thread, the application works fine (see the thenApplyAsync note in the code). > This issue seems already be an issue for another user who reported this in a StackOverflow question: http://stackoverflow.com/questions/32031846/apaches-httpasyncclient-never-returns-after-execute > See the following log when it blocks: > {noformat} > IM-WEBAPP 2017-01-20 09:27:44,506 [I/O dispatcher 1] DEBUG org.apache.http.impl.nio.client.MainClientExec - [exchange: 4] start execution > IM-WEBAPP 2017-01-20 09:27:44,507 [I/O dispatcher 1] DEBUG org.apache.http.client.protocol.RequestAddCookies - CookieSpec selected: default > IM-WEBAPP 2017-01-20 09:27:44,507 [I/O dispatcher 1] DEBUG org.apache.http.client.protocol.RequestAuthCache - Auth cache not set in the context > IM-WEBAPP 2017-01-20 09:27:44,507 [I/O dispatcher 1] DEBUG org.apache.http.impl.nio.client.InternalHttpAsyncClient - [exchange: 4] Request connection for {tls}->http://localhost:3128->https://permissions-api.apps.bosch-iot-cloud.com:443 > IM-WEBAPP 2017-01-20 09:27:44,507 [I/O dispatcher 1] DEBUG org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager - Connection request: [route: {tls}->http://localhost:3128->https://permissions-api.apps.bosch-iot-cloud.com:443][total kept alive: 1; route allocated: 1 of 20; total allocated: 1 of 200] > IM-WEBAPP 2017-01-20 09:27:44,507 [I/O dispatcher 1] DEBUG org.apache.http.impl.nio.conn.ManagedNHttpClientConnectionImpl - http-outgoing-0 127.0.0.1:57860<->127.0.0.1:3128[ACTIVE][r:r][ACTIVE][r][NOT_HANDSHAKING][0][0][0][0]: Set timeout 0 > IM-WEBAPP 2017-01-20 09:27:44,507 [I/O dispatcher 1] DEBUG org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager - Connection leased: [id: http-outgoing-0][route: {tls}->http://localhost:3128->https://permissions-api.apps.bosch-iot-cloud.com:443][total kept alive: 0; route allocated: 1 of 20; total allocated: 1 of 200] > IM-WEBAPP 2017-01-20 09:27:44,507 [I/O dispatcher 1] DEBUG org.apache.http.impl.nio.client.InternalHttpAsyncClient - [exchange: 4] Connection allocated: CPoolProxy{http-outgoing-0 [ACTIVE]} > IM-WEBAPP 2017-01-20 09:27:44,507 [I/O dispatcher 1] DEBUG org.apache.http.impl.nio.conn.ManagedNHttpClientConnectionImpl - http-outgoing-0 127.0.0.1:57860<->127.0.0.1:3128[ACTIVE][r:r][ACTIVE][r][NOT_HANDSHAKING][0][0][0][0]: Set attribute http.nio.exchange-handler > IM-WEBAPP 2017-01-20 09:27:44,508 [I/O dispatcher 1] DEBUG org.apache.http.impl.nio.conn.ManagedNHttpClientConnectionImpl - http-outgoing-0 127.0.0.1:57860<->127.0.0.1:3128[ACTIVE][rw:r][ACTIVE][rw][NOT_HANDSHAKING][0][0][0][0]: Event set [w] > {noformat} > The stack of the blocking thread: > {noformat} > Thread [I/O dispatcher 1] (Suspended) > sun.misc.Unsafe.park(boolean, long) line: not available [native method] > java.util.concurrent.locks.LockSupport.park(java.lang.Object) line: 175 > java.util.concurrent.CompletableFuture$Signaller.block() line: 1693 > java.util.concurrent.ForkJoinPool.managedBlock(java.util.concurrent.ForkJoinPool$ManagedBlocker) line: 3323 > java.util.concurrent.CompletableFuture.waitingGet(boolean) line: 1729 > java.util.concurrent.CompletableFuture.get() line: 1895 > BlockingThreadMainApplication.lambda$0(org.apache.http.impl.nio.client.CloseableHttpAsyncClient, java.io.InputStream) line: 60 > BlockingThreadMainApplication$$Lambda$4.1112414583.apply(java.lang.Object) line: not available > java.util.concurrent.CompletableFuture.uniApply(java.util.concurrent.CompletableFuture, java.util.function.Function, java.util.concurrent.CompletableFuture.UniApply) line: 602 > java.util.concurrent.CompletableFuture$UniApply.tryFire(int) line: 577 > java.util.concurrent.CompletableFuture.postComplete() line: 474 > java.util.concurrent.CompletableFuture.complete(T) line: 1962 > BlockingThreadMainApplication$1.completed(org.apache.http.HttpResponse) line: 83 > BlockingThreadMainApplication$1.completed(java.lang.Object) line: 1 > org.apache.http.concurrent.BasicFuture.completed(T) line: 119 > org.apache.http.impl.nio.client.DefaultClientExchangeHandlerImpl.responseCompleted() line: 177 > org.apache.http.nio.protocol.HttpAsyncRequestExecutor.processResponse(org.apache.http.nio.NHttpClientConnection, org.apache.http.nio.protocol.HttpAsyncRequestExecutor$State, org.apache.http.nio.protocol.HttpAsyncClientExchangeHandler) line: 436 > org.apache.http.nio.protocol.HttpAsyncRequestExecutor.inputReady(org.apache.http.nio.NHttpClientConnection, org.apache.http.nio.ContentDecoder) line: 326 > org.apache.http.impl.nio.client.InternalRequestExecutor.inputReady(org.apache.http.nio.NHttpClientConnection, org.apache.http.nio.ContentDecoder) line: 83 > org.apache.http.impl.nio.conn.ManagedNHttpClientConnectionImpl(org.apache.http.impl.nio.DefaultNHttpClientConnection).consumeInput(org.apache.http.nio.NHttpClientEventHandler) line: 265 > org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(org.apache.http.impl.nio.DefaultNHttpClientConnection) line: 81 > org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(java.lang.Object) line: 39 > org.apache.http.impl.nio.client.InternalIODispatch(org.apache.http.impl.nio.reactor.AbstractIODispatch).inputReady(org.apache.http.nio.reactor.IOSession) line: 121 > org.apache.http.impl.nio.reactor.BaseIOReactor.readable(java.nio.channels.SelectionKey) line: 162 > org.apache.http.impl.nio.reactor.BaseIOReactor(org.apache.http.impl.nio.reactor.AbstractIOReactor).processEvent(java.nio.channels.SelectionKey) line: 337 > org.apache.http.impl.nio.reactor.BaseIOReactor(org.apache.http.impl.nio.reactor.AbstractIOReactor).processEvents(java.util.Set) line: 315 > org.apache.http.impl.nio.reactor.BaseIOReactor(org.apache.http.impl.nio.reactor.AbstractIOReactor).execute() line: 276 > org.apache.http.impl.nio.reactor.BaseIOReactor.execute(org.apache.http.nio.reactor.IOEventDispatch) line: 104 > org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run() line: 588 > java.lang.Thread.run() line: 745 > {noformat} > Be aware that this issue could sometimes be a Heisenbug and the application terminates successfully in debugging. When running normally it fails on my machine with 100%. > You can simply reproduce this issue with the following code or use the attached maven project: > {code:java} > import java.io.IOException; > import java.io.InputStream; > import java.util.concurrent.CompletableFuture; > import java.util.concurrent.ExecutionException; > import org.apache.http.HttpHost; > import org.apache.http.HttpResponse; > import org.apache.http.client.config.RequestConfig; > import org.apache.http.client.methods.HttpGet; > import org.apache.http.concurrent.FutureCallback; > import org.apache.http.impl.nio.client.CloseableHttpAsyncClient; > import org.apache.http.impl.nio.client.HttpAsyncClientBuilder; > import org.apache.http.impl.nio.conn.PoolingNHttpClientConnectionManager; > import org.apache.http.impl.nio.reactor.DefaultConnectingIOReactor; > import org.apache.http.nio.reactor.IOReactorException; > public class BlockingThreadMainApplication > { > private static final int POOL_PER_ROUTE = 20; > private static final int POOL_MAX = 200; > private static final int CONNECT_TIMEOUT = 10000; > private static final int SOCKET_TIMEOUT = 60000; > private static final String PUBLIC_KEYS_URL = "https://permissions-api.apps.bosch-iot-cloud.com/2/rest/publickeys"; > private static HttpHost proxy = null; > private int requestCounter = 0; > public static void main(final String[] args) throws InterruptedException, ExecutionException, IOException > { > // include this lines if you are behind a proxy server > // proxy = new HttpHost("localhost", 3128); > final BlockingThreadMainApplication application = new BlockingThreadMainApplication(); > try (CloseableHttpAsyncClient asyncClient = application.createAsynClient()) > { > // these request work like they should > application.createRequest(asyncClient).get(); > application.createRequest(asyncClient).get(); > System.out.println("Execute request with inner request"); > final Object object = application.createRequestWithInnerRequest(asyncClient).get(); > // will never be invoked > System.out.println("Yeaha, application completed. Resolved last response " + object.getClass().getName()); > } > } > private CompletableFuture createRequestWithInnerRequest(final CloseableHttpAsyncClient asyncClient) > throws InterruptedException, ExecutionException > { > // it works like a charm when using thenApplyAsync so it is executed in another thread > return createRequest(asyncClient).thenApply(i -> > { > // execute another request and get its result > try > { > System.out.println("executing request in thenApply"); > createRequest(asyncClient).get(); // never comes back > System.out.println("executed request in thenApply"); > } > catch (InterruptedException | ExecutionException e) > { > throw new IllegalStateException(e); > } > return i; > }); > } > public CompletableFuture createRequest(final CloseableHttpAsyncClient asyncClient) > { > final int requestId = ++requestCounter; > final CompletableFuture toBeCompleted = new CompletableFuture<>(); > final FutureCallback callback = new FutureCallback() > { > @Override > public void completed(final HttpResponse response) > { > System.out.println("completed " + requestId); > try > { > toBeCompleted.complete(response.getEntity().getContent()); > } > catch (UnsupportedOperationException | IOException e) > { > System.out.println("failed to get InputStream from response " + requestId); > toBeCompleted.completeExceptionally(e); > } > } > @Override > public void cancelled() > { > System.out.println("cancelled " + requestId); > toBeCompleted.cancel(true); > } > @Override > public void failed(final Exception e) > { > System.out.println("failed " + requestId); > toBeCompleted.completeExceptionally(e); > } > }; > asyncClient.execute(getGetRequest(), callback); > return toBeCompleted; > } > private CloseableHttpAsyncClient createAsynClient() > { > // Create common default configuration > final RequestConfig clientConfig = RequestConfig.custom().setConnectTimeout(CONNECT_TIMEOUT) > .setSocketTimeout(SOCKET_TIMEOUT).setConnectionRequestTimeout(SOCKET_TIMEOUT).setProxy(proxy).build(); > DefaultConnectingIOReactor ioreactor; > PoolingNHttpClientConnectionManager asyncConnectionManager; > try > { > ioreactor = new DefaultConnectingIOReactor(); > asyncConnectionManager = new PoolingNHttpClientConnectionManager(ioreactor); > asyncConnectionManager.setMaxTotal(POOL_MAX); > asyncConnectionManager.setDefaultMaxPerRoute(POOL_PER_ROUTE); > } > catch (final IOReactorException e) > { > throw new RuntimeException(e); > } > final CloseableHttpAsyncClient client = HttpAsyncClientBuilder.create().setDefaultRequestConfig(clientConfig) > .setConnectionManager(asyncConnectionManager).build(); > client.start(); > return client; > } > private HttpGet getGetRequest() > { > return new HttpGet(PUBLIC_KEYS_URL); > } > } > {code} > I don't think it is related to HTTPASYNC-35 or HTTPASYNC-34 who sounds similiar. > Just one last note: Why is 4.1.2 released but not in this Jira project? -- This message was sent by Atlassian JIRA (v6.3.4#6332) --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscribe@hc.apache.org For additional commands, e-mail: dev-help@hc.apache.org