[
https://issues.apache.org/jira/browse/HTTPCLIENT-2416?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18063006#comment-18063006
]
Arturo Bernal commented on HTTPCLIENT-2416:
-------------------------------------------
[~olegk]
Agreed — I don’t think this is an HttpComponents defect per se. It’s a race
inherent to cancellation / timeouts: a lease can complete concurrently with
{{Future.get()}} timing out or being interrupted, and the caller never gets an
endpoint to release.
That said, I prototyped a very small defensive mitigation in
{{PoolingHttpClientConnectionManager#lease()}} on the exceptional path: when
{{leaseFuture.get(..)}} throws {{TimeoutException}} or
{{{}InterruptedException{}}}, we call {{{}leaseFuture.cancel(true){}}}; if
{{cancel()}} returns {{false}} (meaning completion won the race), I try a
zero-timeout {{leaseFuture.get(0, MILLISECONDS)}} and if it returns a
{{PoolEntry}} I immediately {{pool.release(entry, false)}} to avoid a stranded
lease.
https://github.com/arturobernalg/httpcomponents-client/commit/d026364dd0e9003bf828bdb0fe62b0a71b44bae2
Thanks,
Arturo
> 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,
> TimeoutLeakExample.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]