1

I use async http client in my code to asynchronously handle GET responses I can run simultaneously 100 requests in the same time.

I use just on instance of httpClient in container

@Bean(destroyMethod = "close")
open fun httpClient() = Dsl.asyncHttpClient()

Code looks like

fun method(): CompletableFuture<String> {
    return httpClient.prepareGet("someUrl").execute()
        .toCompletableFuture()
        .thenApply(::getResponseBody)
}

It works fine functionally. In my testing I use mock endpoint with the same url address. But my expectation was that all the requests are handled in several threads, but in profiler I can see that 16 threads are created for AsyncHttpClient, and they aren't destroyed, even if there are no requests to send.

profiler screenshoot

My expectation was that

  • it will be less threads for async client
  • threads will be destroyed after some configured timeout
  • is there some option to control how much threads can be created by asyncHttpClient?

Am I missing something in my expectations?

UPDATE 1 I saw instruction on https://github.com/AsyncHttpClient/async-http-client/wiki/Connection-pooling I found no info on thread pool

UPDATE 2 I also created method to do the same, but with handler and additional executor pool

Utility method look like

fun <Value, Result> CompletableFuture<Value>.handleResultAsync(executor: Executor, initResultHandler: ResultHandler<Value, Result>.() -> Unit): CompletableFuture<Result> {
    val rh = ResultHandler<Value, Result>()
    rh.initResultHandler()

    val handler = BiFunction { value: Value?, exception: Throwable? ->
        if (exception == null) rh.success?.invoke(value) else rh.fail?.invoke(exception)
    }

    return handleAsync(handler, executor)
}

The updated method look like

fun method(): CompletableFuture<String> {
    return httpClient.prepareGet("someUrl").execute()
        .toCompletableFuture()
        .handleResultAsync(executor) {
            success = {response ->
                logger.info("ok")
                getResponseBody(response!!)
            }
            fail = { ex ->
                logger.error("Failed to execute request", ex)
                throw ex
            }
    }
}

Then I can see that result of GET method is executed in the threads provided by thread pool (previously result was executed in "AsyncHttpClient-3-x"), but additional thread for AsyncHttpClient are still created and not destroyed.

user2105282
  • 724
  • 1
  • 12
  • 26
  • https://github.com/AsyncHttpClient/async-http-client/wiki/Connection-pooling describes how to set up the connection pools and thread pools – PJ Fanning May 28 '19 at 13:42
  • I saw the page, but there is nothing about tread pools? – user2105282 May 28 '19 at 13:45
  • Have you checked https://stackoverflow.com/questions/35431414/does-asynchttpclient-knows-how-many-threads-to-allocate-for-all-the-http-request ? – PJ Fanning May 28 '19 at 13:53
  • 1
    Yes, but still can't understand how it is connected with number of threads. So in my case I have only requests to one host. So in the link provided it is written that should be only one thread, which can handle all the requests. Or all the threads are initialised by default and can be used by AsyncClient to perform it internal job? – user2105282 May 28 '19 at 14:04

1 Answers1

2

AHC has two types of threads:

  1. For I/O operation. On your screen, it's AsyncHttpClient-x-x threads. AHC creates 2*core_number of those.
  2. For timeouts. On your screen, it's AsyncHttpClient-timer-1-1 thread. Should be only one.

Source: issue on GitHub: https://github.com/AsyncHttpClient/async-http-client/issues/1658

Mike Mike
  • 598
  • 7
  • 15
  • Thanks a lot. This completely describes the profiler threads picture, as I have 8 Cores on the machine, on which the code was executed – user2105282 Aug 14 '19 at 08:56