[ 
https://issues.apache.org/jira/browse/HTTPCLIENT-2416?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18062747#comment-18062747
 ] 

Benjamin Peterson commented on HTTPCLIENT-2416:
-----------------------------------------------

With regards to request cancellation, is this what you mean?
{code:java}
  private static void doRequest(CloseableHttpClient httpClient) throws 
IOException, ParseException {
    var httpGet = new HttpGet("https://www.example.com";);
    try (var response = httpClient.execute(httpGet)) {
      var entity = response.getEntity();
      if (entity != null) {
        EntityUtils.toString(entity);
      }
    } finally {
      httpGet.cancel();
    }
  }
{code}
(I added {{httpGet.cancel()}} to a {{finally}} block.) Doing that certainly 
reduces the leaking, but I'm still left with some leaked connections:
{noformat}
=== Initial Connection Pool Stats ===
Available: 0
Leased: 0
Pending: 0
Max: 2

=== Starting 10000 parallel requests ===

=== Results ===
Total requests: 10000
Successful: 0
Failed: 9940

=== Final Connection Pool Stats ===
Available: 0
Leased: 2
Pending: 7961
Max: 2

=== Attempting another request ===
[hang]
{noformat}

It's not so much question of how I would prefer to cancel requests as how 
layers above my code have decided to do cancelation. For better or worse, Java 
allows any thread to be interrupted at any time. Does httpcomponents-client 
strive to safely support thread interruption? The careful handling in the 
connection pools and `InternalExecRuntime` makes it look like that.

With regards to seriousness, my experience is that leaking connections from a 
{{StrictConnPool}} eventually will completely break an application. And it's an 
insidiously difficult issue to debug.

> interrupts and timeouts may leak connections
> --------------------------------------------
>
>                 Key: HTTPCLIENT-2416
>                 URL: https://issues.apache.org/jira/browse/HTTPCLIENT-2416
>             Project: HttpComponents HttpClient
>          Issue Type: Bug
>    Affects Versions: 5.6
>            Reporter: Benjamin Peterson
>            Priority: Minor
>         Attachments: HttpGetExample.java, HttpGetExample2.java
>
>
> Consider {{InternalExecRuntime.acquireEndpoint}}:
> {code:java}
>             try {
>                 final ConnectionEndpoint connectionEndpoint = 
> connRequest.get(connectionRequestTimeout);
>             } catch (final TimeoutException ex) {
>                 connRequest.cancel();
>                 throw new ConnectionRequestTimeoutException(ex.getMessage());
>             } catch (final InterruptedException interrupted) {
>                 connRequest.cancel();
>                 Thread.currentThread().interrupt();
>                 throw new RequestFailedException("Request aborted", 
> interrupted);
>             }
> {code}
> Consider this order of operations:
> 1. The thread blocked in {{codeRequest.get}} is interrupted or times out.
> 2. The connection pool completes the future with a connection.
> 3. The interrupted thread starts propagating the {{InterruptedException}} or 
> {{TimeoutException}}. When it reaches the {{catch}} blocks, it will call 
> {{connRequest.cancel()}}. But cancelation will do nothing because the 
> connection pool already completed the future. The connection will leak.
> The window may be narrow, but it's certainly a possibility if heavy load 
> means the blocked thread is delayed in being scheduled to propagate the 
> {{InterruptedException}} or {{TimeoutException}}.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to