Java 11 HttpClient Http2 Too many streams Error

Unfortunately, the approach with Semaphore, suggested by @sbordet, didn't work for me. I tried this:

var semaphore = semaphores.computeIfAbsent(getRequestKey(request), k -> new Semaphore(MAX_CONCURRENT_REQUESTS_NUMBER));

CompletableFuture.runAsync(semaphore::acquireUninterruptibly, WAITING_POOL)
                .thenComposeAsync(ignored -> httpClient.sendAsync(request, responseBodyHandler), ASYNC_POOL)
                .whenComplete((response, e) -> semaphore.release());

There's no guarantee that a connection stream is released by the time the execution is passed to the next CompletableFuture, where the semaphore is released. For me the approach worked in case of normal execution, however if there're any exceptions, it seems that the connection stream may be closed after semaphore.release() is invoked.

Finally, I ended up by using OkHttp. It handles the problem (it just waits until some streams are freed up if the number of concurrent streams reaches max_concurrent_streams). It also handles the GOAWAY frame. In case of Java HttpClient I had to implement retry logic to handle this as it just throws IOException if the server sends GOAWAY frame.


When I try to hit the server continuously

The server has a setting for max_concurrent_streams that is communicated to the client during the initial establishment of a HTTP/2 connection.

If you blindly "hit the server continuously" using sendAsync you are not waiting for previous requests to finish and eventually you exceed the max_concurrent_streams value and receive the error above.

The solution is to send concurrently a number of requests that is less than max_concurrent_streams; after that, you only send a new request when a previous one completes. This can easily implemented on the client using a Semaphore or something similar.