diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/config/ConnectionConfig.java b/httpclient5/src/main/java/org/apache/hc/client5/http/config/ConnectionConfig.java index 4be79544a8..5c2f654985 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/config/ConnectionConfig.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/config/ConnectionConfig.java @@ -48,6 +48,7 @@ public class ConnectionConfig implements Cloneable { private final Timeout connectTimeout; private final Timeout socketTimeout; + private final Timeout idleTimeout; private final TimeValue validateAfterInactivity; private final TimeValue timeToLive; @@ -55,17 +56,19 @@ public class ConnectionConfig implements Cloneable { * Intended for CDI compatibility */ protected ConnectionConfig() { - this(DEFAULT_CONNECT_TIMEOUT, null, null, null); + this(DEFAULT_CONNECT_TIMEOUT, null, null, null, null); } ConnectionConfig( final Timeout connectTimeout, final Timeout socketTimeout, + final Timeout idleTimeout, final TimeValue validateAfterInactivity, final TimeValue timeToLive) { super(); this.connectTimeout = connectTimeout; this.socketTimeout = socketTimeout; + this.idleTimeout = idleTimeout; this.validateAfterInactivity = validateAfterInactivity; this.timeToLive = timeToLive; } @@ -84,6 +87,13 @@ public Timeout getConnectTimeout() { return connectTimeout; } + /** + * @see Builder#setIdleTimeout(Timeout) + */ + public Timeout getIdleTimeout() { + return idleTimeout; + } + /** * @see Builder#setValidateAfterInactivity(TimeValue) */ @@ -109,6 +119,7 @@ public String toString() { builder.append("["); builder.append("connectTimeout=").append(connectTimeout); builder.append(", socketTimeout=").append(socketTimeout); + builder.append(", idleTimeout=").append(idleTimeout); builder.append(", validateAfterInactivity=").append(validateAfterInactivity); builder.append(", timeToLive=").append(timeToLive); builder.append("]"); @@ -131,6 +142,7 @@ public static class Builder { private Timeout socketTimeout; private Timeout connectTimeout; + private Timeout idleTimeout; private TimeValue validateAfterInactivity; private TimeValue timeToLive; @@ -194,6 +206,35 @@ public Builder setConnectTimeout(final long connectTimeout, final TimeUnit timeU return this; } + /** + * Determines the maximum period of idleness for a connection. + * Connections that are idle for longer than {@code idleTimeout} are no + * longer eligible for reuse. + *

+ * A timeout value of zero is interpreted as an infinite timeout. + *

+ *

+ * Default: {@code null} (undefined) + *

+ * + * @return this instance. + * + * @since 5.6 + */ + public Builder setIdleTimeout(final Timeout idleTimeout) { + this.idleTimeout = idleTimeout; + return this; + } + + /** + * @return this instance. + * @see #setIdleTimeout(Timeout) + */ + public Builder setIdleTimeout(final long idleTimeout, final TimeUnit timeUnit) { + this.idleTimeout = Timeout.of(idleTimeout, timeUnit); + return this; + } + /** * Defines period of inactivity after which persistent connections must * be re-validated prior to being leased to the consumer. Negative values passed @@ -244,6 +285,7 @@ public ConnectionConfig build() { return new ConnectionConfig( connectTimeout != null ? connectTimeout : DEFAULT_CONNECT_TIMEOUT, socketTimeout, + idleTimeout, validateAfterInactivity, timeToLive); } diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManager.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManager.java index 2977f5f196..ecd134f86b 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManager.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManager.java @@ -391,6 +391,14 @@ public ConnectionEndpoint get( } } } + if (poolEntry.hasConnection()) { + final TimeValue idleTimeout = connectionConfig.getIdleTimeout(); + if (TimeValue.isPositive(idleTimeout)) { + if (Deadline.calculate(poolEntry.getUpdated(), idleTimeout).isExpired()) { + poolEntry.discardConnection(CloseMode.GRACEFUL); + } + } + } if (poolEntry.hasConnection()) { final TimeValue timeValue = resolveValidateAfterInactivity(connectionConfig); if (TimeValue.isNonNegative(timeValue)) { diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManager.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManager.java index ce0e4d1e29..feda279e28 100644 --- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManager.java +++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManager.java @@ -300,6 +300,14 @@ public void completed(final PoolEntry p } } } + if (poolEntry.hasConnection()) { + final TimeValue idleTimeout = connectionConfig.getIdleTimeout(); + if (TimeValue.isPositive(idleTimeout)) { + if (Deadline.calculate(poolEntry.getUpdated(), idleTimeout).isExpired()) { + poolEntry.discardConnection(CloseMode.GRACEFUL); + } + } + } if (poolEntry.hasConnection()) { final ManagedAsyncClientConnection connection = poolEntry.getConnection(); final TimeValue timeValue = connectionConfig.getValidateAfterInactivity();