You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2026/09/28 16:10:53 UTC

(httpcomponents-client) branch master updated: Removed the initial implementation of #evictIdleConnections in H2AsyncClientBuilder as it can cause premature termination of connections with multiplexing message exchanges; added #evictExpiredConnections to proactively evict expired connections from the connection pool

This is an automated email from the ASF dual-hosted git repository.

ok2c pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git


The following commit(s) were added to refs/heads/master by this push:
     new 8b64f5991 Removed the initial implementation of #evictIdleConnections in H2AsyncClientBuilder as it can cause premature termination of connections with multiplexing message exchanges; added #evictExpiredConnections to proactively evict expired connections from the connection pool
8b64f5991 is described below

commit 8b64f599175165c91367a92b5e79640d5eda83c0
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Mon Sep 28 17:59:50 2026 +0200

    Removed the initial implementation of #evictIdleConnections in H2AsyncClientBuilder as it can cause premature termination of connections with multiplexing message exchanges; added #evictExpiredConnections to proactively evict expired connections from the connection pool
---
 .../http/impl/async/H2AsyncClientBuilder.java      | 61 ++++++++++++----------
 .../http/impl/async/InternalH2ConnPool.java        |  6 ++-
 2 files changed, 37 insertions(+), 30 deletions(-)

diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/H2AsyncClientBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/H2AsyncClientBuilder.java
index c439bc89c..ed52ed54d 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/H2AsyncClientBuilder.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/H2AsyncClientBuilder.java
@@ -197,8 +197,7 @@ private ExecInterceptorEntry(
     private Collection<? extends Header> defaultHeaders;
     private RequestConfig defaultRequestConfig;
     private Resolver<HttpHost, ConnectionConfig> connectionConfigResolver;
-    private boolean evictIdleConnections;
-    private TimeValue maxIdleTime;
+    private boolean evictExpiredConnections;
 
     private boolean automaticRetriesDisabled;
     private boolean redirectHandlingDisabled;
@@ -212,7 +211,6 @@ private ExecInterceptorEntry(
 
     private List<Closeable> closeables;
 
-
     private Callback<Exception> ioReactorExceptionCallback;
 
     private Decorator<IOSession> ioSessionDecorator;
@@ -718,33 +716,39 @@ public final H2AsyncClientBuilder disableAuthCaching() {
     }
 
     /**
-     * Makes this instance of HttpClient proactively evict idle connections from the
-     * connection pool using a background thread.
-     * <p>
-     * One MUST explicitly close HttpClient with {@link CloseableHttpAsyncClient#close()}
-     * in order to stop and release the background thread.
-     * </p>
-     * <p>
-     * Please note this method has no effect if the instance of HttpClient is configured to
-     * use a shared connection manager.
-     * </p>
+     * This method has no effect. Its initial implementation has been removed, as it can
+     * cause premature termination of sessions with multiplexing message exchanges.
      *
-     * @param maxIdleTime maximum time persistent connections can stay idle while kept alive
-     * in the connection pool. Connections whose inactivity period exceeds this value will
-     * get closed and evicted from the pool.
+     * @deprecated This method has no effect as of version 5.7 and should not be used.
+     * Use {{@link ConnectionConfig#getSocketTimeout()}} to ensure idle connections time out
+     * and get gracefully terminated. Use {@link #evictExpiredConnections()} to proactively
+     * evict expired (closed) connections if required.
      *
-     * @return this instance.
-     * @deprecated Configure connection keep-alive settings appropriately and use
-     * {@link #evictExpiredConnections()} instead.
-     * @see RequestConfig#getConnectionKeepAlive()
+     * @see ConnectionConfig#getSocketTimeout()
      */
     @Deprecated
     public final H2AsyncClientBuilder evictIdleConnections(final TimeValue maxIdleTime) {
-        this.evictIdleConnections = true;
-        this.maxIdleTime = maxIdleTime;
         return this;
     }
 
+    /**
+     * Makes this instance of HttpClient proactively evict expired connections from the
+     * connection pool using a background thread.
+     * <p>
+     * Use {{@link ConnectionConfig#getSocketTimeout()}} to ensure idle connections time out
+     * and get gracefully terminated.
+     * <p>
+     * One MUST explicitly close HttpClient with {@link CloseableHttpAsyncClient#close()} in order
+     * to stop and release the background thread.
+     *
+     * @return this instance.
+     *
+     * @since 5.7
+     */
+    public final H2AsyncClientBuilder evictExpiredConnections() {
+        this.evictExpiredConnections = true;
+        return this;
+    }
 
     /**
      * Request exec chain customization and extension.
@@ -982,9 +986,8 @@ public CloseableHttpAsyncClient build() {
         if (closeablesCopy == null) {
             closeablesCopy = new ArrayList<>(1);
         }
-        if (evictIdleConnections) {
-            final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor(connPool,
-                    maxIdleTime != null ? maxIdleTime : TimeValue.ofSeconds(30L));
+        if (evictExpiredConnections) {
+            final IdleConnectionEvictor connectionEvictor = new IdleConnectionEvictor(connPool);
             closeablesCopy.add(connectionEvictor::shutdown);
             connectionEvictor.start();
         }
@@ -1008,16 +1011,18 @@ public CloseableHttpAsyncClient build() {
 
     }
 
+    private static final TimeValue ONE_MINUTE = TimeValue.ofMinutes(1L);
+
     static class IdleConnectionEvictor implements Closeable {
 
         private final Thread thread;
 
-        public IdleConnectionEvictor(final InternalH2ConnPool connPool, final TimeValue maxIdleTime) {
+        public IdleConnectionEvictor(final InternalH2ConnPool connPool) {
             this.thread = new DefaultThreadFactory("idle-connection-evictor", true).newThread(() -> {
                 try {
                     while (!Thread.currentThread().isInterrupted()) {
-                        maxIdleTime.sleep();
-                        connPool.closeIdle(maxIdleTime);
+                        ONE_MINUTE.sleep();
+                        connPool.evictExpired();
                     }
                 } catch (final InterruptedException ex) {
                     Thread.currentThread().interrupt();
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalH2ConnPool.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalH2ConnPool.java
index 97c6981ff..b1f3357a5 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalH2ConnPool.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/InternalH2ConnPool.java
@@ -102,8 +102,10 @@ public void completed(final IOSession ioSession) {
                 });
     }
 
-    public void closeIdle(final TimeValue idleTime) {
-        sessionPool.closeIdle(idleTime);
+    public void evictExpired() {
+        sessionPool.enumAvailable(e -> {
+            // no op
+        });
     }
 
     public void setConnectionConfigResolver(final Resolver<HttpHost, ConnectionConfig> connectionConfigResolver) {