[prev in list] [next in list] [prev in thread] [next in thread]
List: httpcomponents-commits
Subject: [httpcomponents-client] 01/02: Support for connection TTL setting on a per-route basis
From: olegk () apache ! org
Date: 2021-10-23 17:53:16
Message-ID: 20211023175315.514E880541 () gitbox ! apache ! org
[Download RAW message or body]
This is an automated email from the ASF dual-hosted git repository.
olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git
commit a02455acb31ad7e676130d46d6a04bd97b76e957
Author: Oleg Kalnichevski <olegk@apache.org>
AuthorDate: Sat Oct 23 15:57:00 2021 +0200
Support for connection TTL setting on a per-route basis
---
.../hc/client5/http/config/ConnectionConfig.java | 41 ++++++++++++--
.../impl/io/BasicHttpClientConnectionManager.java | 64 ++++++++++++++++------
.../io/PoolingHttpClientConnectionManager.java | 40 +++++++++-----
.../PoolingHttpClientConnectionManagerBuilder.java | 11 ++--
.../nio/PoolingAsyncClientConnectionManager.java | 44 ++++++++++-----
...PoolingAsyncClientConnectionManagerBuilder.java | 10 +++-
6 files changed, 153 insertions(+), 57 deletions(-)
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 38ead6f..126b38d 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
@@ -49,22 +49,25 @@ public class ConnectionConfig implements Cloneable {
private final Timeout connectTimeout;
private final Timeout socketTimeout;
private final TimeValue validateAfterInactivity;
+ private final TimeValue timeToLive;
/**
* Intended for CDI compatibility
*/
protected ConnectionConfig() {
- this(DEFAULT_CONNECT_TIMEOUT, null, null);
+ this(DEFAULT_CONNECT_TIMEOUT, null, null, null);
}
ConnectionConfig(
final Timeout connectTimeout,
final Timeout socketTimeout,
- final TimeValue validateAfterInactivity) {
+ final TimeValue validateAfterInactivity,
+ final TimeValue timeToLive) {
super();
this.connectTimeout = connectTimeout;
this.socketTimeout = socketTimeout;
this.validateAfterInactivity = validateAfterInactivity;
+ this.timeToLive = timeToLive;
}
/**
@@ -88,6 +91,13 @@ public class ConnectionConfig implements Cloneable {
return validateAfterInactivity;
}
+ /**
+ * @see Builder#setTimeToLive(TimeValue) (TimeValue)
+ */
+ public TimeValue getTimeToLive() {
+ return timeToLive;
+ }
+
@Override
protected ConnectionConfig clone() throws CloneNotSupportedException {
return (ConnectionConfig) super.clone();
@@ -100,6 +110,7 @@ public class ConnectionConfig implements Cloneable {
builder.append(", connectTimeout=").append(connectTimeout);
builder.append(", socketTimeout=").append(socketTimeout);
builder.append(", \
validateAfterInactivity=").append(validateAfterInactivity); + \
builder.append(", timeToLive=").append(timeToLive); builder.append("]");
return builder.toString();
}
@@ -112,7 +123,8 @@ public class ConnectionConfig implements Cloneable {
return new Builder()
.setConnectTimeout(config.getConnectTimeout())
.setSocketTimeout(config.getSocketTimeout())
- .setValidateAfterInactivity(config.getValidateAfterInactivity());
+ .setValidateAfterInactivity(config.getValidateAfterInactivity())
+ .setTimeToLive(config.getTimeToLive());
}
public static class Builder {
@@ -120,6 +132,7 @@ public class ConnectionConfig implements Cloneable {
private Timeout socketTimeout;
private Timeout connectTimeout;
private TimeValue validateAfterInactivity;
+ private TimeValue timeToLive;
Builder() {
super();
@@ -190,11 +203,31 @@ public class ConnectionConfig implements Cloneable {
return this;
}
+ /**
+ * Defines the total span of time connections can be kept alive or execute \
requests. + * <p>
+ * Default: {@code null} (undefined)
+ * </p>
+ */
+ public Builder setTimeToLive(final TimeValue timeToLive) {
+ this.timeToLive = timeToLive;
+ return this;
+ }
+
+ /**
+ * @see #setTimeToLive(TimeValue)
+ */
+ public Builder setTimeToLive(final long timeToLive, final TimeUnit timeUnit) \
{ + this.timeToLive = TimeValue.of(timeToLive, timeUnit);
+ return this;
+ }
+
public ConnectionConfig build() {
return new ConnectionConfig(
connectTimeout != null ? connectTimeout : \
DEFAULT_CONNECT_TIMEOUT, socketTimeout,
- validateAfterInactivity);
+ validateAfterInactivity,
+ timeToLive);
}
}
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/BasicHttpClientConnectionManager.java \
b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/BasicHttpClientConnectionManager.java
index a67b3ad..cfa82dc 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/BasicHttpClientConnectionManager.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/BasicHttpClientConnectionManager.java
@@ -67,6 +67,7 @@ import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.io.CloseMode;
import org.apache.hc.core5.util.Args;
import org.apache.hc.core5.util.Asserts;
+import org.apache.hc.core5.util.Deadline;
import org.apache.hc.core5.util.LangUtils;
import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;
@@ -105,6 +106,7 @@ public class BasicHttpClientConnectionManager implements \
HttpClientConnectionMan private ManagedHttpClientConnection conn;
private HttpRoute route;
private Object state;
+ private long created;
private long updated;
private long expiry;
private boolean leased;
@@ -114,8 +116,6 @@ public class BasicHttpClientConnectionManager implements \
HttpClientConnectionMan
private final AtomicBoolean closed;
- private volatile TimeValue validateAfterInactivity;
-
private static Registry<ConnectionSocketFactory> getDefaultRegistry() {
return RegistryBuilder.<ConnectionSocketFactory>create()
.register(URIScheme.HTTP.id, \
PlainConnectionSocketFactory.getSocketFactory()) @@ -147,7 +147,6 @@ public class \
BasicHttpClientConnectionManager implements HttpClientConnectionMan \
this.connectionConfig = ConnectionConfig.DEFAULT; this.tlsConfig = \
TlsConfig.DEFAULT; this.closed = new AtomicBoolean(false);
- this.validateAfterInactivity = TimeValue.ofSeconds(2L);
}
public BasicHttpClientConnectionManager(
@@ -210,6 +209,13 @@ public class BasicHttpClientConnectionManager implements \
HttpClientConnectionMan /**
* @since 5.2
*/
+ public synchronized TlsConfig getTlsConfig() {
+ return tlsConfig;
+ }
+
+ /**
+ * @since 5.2
+ */
public synchronized void setTlsConfig(final TlsConfig tlsConfig) {
this.tlsConfig = tlsConfig != null ? tlsConfig : TlsConfig.DEFAULT;
}
@@ -260,21 +266,34 @@ public class BasicHttpClientConnectionManager implements \
HttpClientConnectionMan }
private void validate() {
- final TimeValue validateAfterInactivitySnapshot = validateAfterInactivity;
- if (this.conn != null
- && TimeValue.isNonNegative(validateAfterInactivitySnapshot)
- && updated + validateAfterInactivitySnapshot.toMilliseconds() <= \
System.currentTimeMillis()) {
- boolean stale;
- try {
- stale = conn.isStale();
- } catch (final IOException ignore) {
- stale = true;
+ if (this.conn != null) {
+ final TimeValue timeToLive = connectionConfig.getTimeToLive();
+ if (TimeValue.isNonNegative(timeToLive)) {
+ final Deadline deadline = Deadline.calculate(created, timeToLive);
+ if (deadline.isExpired()) {
+ closeConnection(CloseMode.GRACEFUL);
+ }
}
- if (stale) {
- if (LOG.isDebugEnabled()) {
- LOG.debug("{} connection {} is stale", id, \
ConnPoolSupport.getId(conn)); + }
+ if (this.conn != null) {
+ final TimeValue timeValue = \
connectionConfig.getValidateAfterInactivity() != null ? + \
connectionConfig.getValidateAfterInactivity() : TimeValue.ofSeconds(2); + \
if (TimeValue.isNonNegative(timeValue)) { + final Deadline deadline = \
Deadline.calculate(updated, timeValue); + if (deadline.isExpired()) {
+ boolean stale;
+ try {
+ stale = conn.isStale();
+ } catch (final IOException ignore) {
+ stale = true;
+ }
+ if (stale) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("{} connection {} is stale", id, \
ConnPoolSupport.getId(conn)); + }
+ closeConnection(CloseMode.GRACEFUL);
+ }
}
- closeConnection(CloseMode.GRACEFUL);
}
}
}
@@ -294,6 +313,7 @@ public class BasicHttpClientConnectionManager implements \
HttpClientConnectionMan validate();
if (this.conn == null) {
this.conn = this.connFactory.createConnection(null);
+ this.created = System.currentTimeMillis();
} else {
this.conn.activate();
}
@@ -436,9 +456,12 @@ public class BasicHttpClientConnectionManager implements \
HttpClientConnectionMan
* @see #setValidateAfterInactivity(TimeValue)
*
* @since 5.1
+ *
+ * @deprecated Use {@link #getConnectionConfig()}
*/
+ @Deprecated
public TimeValue getValidateAfterInactivity() {
- return validateAfterInactivity;
+ return connectionConfig.getValidateAfterInactivity();
}
/**
@@ -448,9 +471,14 @@ public class BasicHttpClientConnectionManager implements \
HttpClientConnectionMan
* detect connections that have become stale (half-closed) while kept inactive \
in the pool.
*
* @since 5.1
+ *
+ * @deprecated Use {@link #setConnectionConfig(ConnectionConfig)}
*/
+ @Deprecated
public void setValidateAfterInactivity(final TimeValue validateAfterInactivity) \
{
- this.validateAfterInactivity = validateAfterInactivity;
+ this.connectionConfig = ConnectionConfig.custom()
+ .setValidateAfterInactivity(validateAfterInactivity)
+ .build();
}
class InternalConnectionEndpoint extends ConnectionEndpoint {
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 8c415fc..626fe98 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
@@ -76,6 +76,7 @@ import org.apache.hc.core5.pool.PoolStats;
import org.apache.hc.core5.pool.StrictConnPool;
import org.apache.hc.core5.util.Args;
import org.apache.hc.core5.util.Asserts;
+import org.apache.hc.core5.util.Deadline;
import org.apache.hc.core5.util.Identifiable;
import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;
@@ -303,23 +304,34 @@ public class PoolingHttpClientConnectionManager
LOG.debug("{} endpoint leased {}", id, \
ConnPoolSupport.formatStats(route, state, pool)); }
final ConnectionConfig connectionConfig = \
resolveConnectionConfig(route);
- final TimeValue timeValue = \
resolveValidateAfterInactivity(connectionConfig); try {
- if (TimeValue.isNonNegative(timeValue)) {
- final ManagedHttpClientConnection conn = \
poolEntry.getConnection();
- if (conn != null
- && poolEntry.getUpdated() + \
timeValue.toMilliseconds() <= System.currentTimeMillis()) {
- boolean stale;
- try {
- stale = conn.isStale();
- } catch (final IOException ignore) {
- stale = true;
+ if (poolEntry.hasConnection()) {
+ final TimeValue timeToLive = \
connectionConfig.getTimeToLive(); + if \
(TimeValue.isNonNegative(timeToLive)) { + final Deadline \
deadline = Deadline.calculate(poolEntry.getCreated(), timeToLive); + \
if (deadline.isExpired()) { + \
poolEntry.discardConnection(CloseMode.GRACEFUL); }
- if (stale) {
- if (LOG.isDebugEnabled()) {
- LOG.debug("{} connection {} is stale", id, \
ConnPoolSupport.getId(conn)); + }
+ }
+ if (poolEntry.hasConnection()) {
+ final TimeValue timeValue = \
resolveValidateAfterInactivity(connectionConfig); + if \
(TimeValue.isNonNegative(timeValue)) { + final Deadline \
deadline = Deadline.calculate(poolEntry.getUpdated(), timeValue); + \
if (deadline.isExpired()) { + final \
ManagedHttpClientConnection conn = poolEntry.getConnection(); + \
boolean stale; + try {
+ stale = conn.isStale();
+ } catch (final IOException ignore) {
+ stale = true;
+ }
+ if (stale) {
+ if (LOG.isDebugEnabled()) {
+ LOG.debug("{} connection {} is stale", id, \
ConnPoolSupport.getId(conn)); + }
+ \
poolEntry.discardConnection(CloseMode.IMMEDIATE); }
- poolEntry.discardConnection(CloseMode.IMMEDIATE);
}
}
}
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManagerBuilder.java \
b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManagerBuilder.java
index c150e23..799c6ba 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManagerBuilder.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/io/PoolingHttpClientConnectionManagerBuilder.java
@@ -90,8 +90,6 @@ public class PoolingHttpClientConnectionManagerBuilder {
private int maxConnTotal;
private int maxConnPerRoute;
- private TimeValue timeToLive;
-
public static PoolingHttpClientConnectionManagerBuilder create() {
return new PoolingHttpClientConnectionManagerBuilder();
}
@@ -229,9 +227,14 @@ public class PoolingHttpClientConnectionManagerBuilder {
/**
* Sets maximum time to live for persistent connections
+ *
+ * @deprecated Use {@link #setDefaultConnectionConfig(ConnectionConfig)}.
*/
+ @Deprecated
public final PoolingHttpClientConnectionManagerBuilder \
setConnectionTimeToLive(final TimeValue timeToLive) {
- this.timeToLive = timeToLive;
+ setDefaultConnectionConfig(ConnectionConfig.custom()
+ .setTimeToLive(timeToLive)
+ .build());
return this;
}
@@ -269,7 +272,7 @@ public class PoolingHttpClientConnectionManagerBuilder {
.build(),
poolConcurrencyPolicy,
poolReusePolicy,
- timeToLive != null ? timeToLive : TimeValue.NEG_ONE_MILLISECOND,
+ null,
schemePortResolver,
dnsResolver,
connectionFactory);
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 3db4ca1..3975859 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
@@ -88,6 +88,7 @@ import org.apache.hc.core5.reactor.ProtocolIOSession;
import org.apache.hc.core5.reactor.ssl.TlsDetails;
import org.apache.hc.core5.util.Args;
import org.apache.hc.core5.util.Asserts;
+import org.apache.hc.core5.util.Deadline;
import org.apache.hc.core5.util.Identifiable;
import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;
@@ -261,25 +262,40 @@ public class PoolingAsyncClientConnectionManager implements \
AsyncClientConnectio
@Override
public void completed(final PoolEntry<HttpRoute, \
ManagedAsyncClientConnection> poolEntry) {
- final ManagedAsyncClientConnection connection = \
poolEntry.getConnection();
- final TimeValue timeValue = connectionConfig != null ? \
connectionConfig.getValidateAfterInactivity() : null;
- if (TimeValue.isNonNegative(timeValue) && connection != \
null &&
- poolEntry.getUpdated() + \
timeValue.toMilliseconds() <= System.currentTimeMillis()) {
- final ProtocolVersion protocolVersion = \
connection.getProtocolVersion();
- if (protocolVersion != null && \
protocolVersion.greaterEquals(HttpVersion.HTTP_2_0)) {
- connection.submitCommand(new PingCommand(new \
BasicPingHandler(result -> {
- if (result == null || !result) {
+ if (poolEntry.hasConnection()) {
+ final TimeValue timeToLive = \
connectionConfig.getTimeToLive(); + if \
(TimeValue.isNonNegative(timeToLive)) { + final \
Deadline deadline = Deadline.calculate(poolEntry.getCreated(), timeToLive); + \
if (deadline.isExpired()) { + \
poolEntry.discardConnection(CloseMode.GRACEFUL); + \
} + }
+ }
+ if (poolEntry.hasConnection()) {
+ final ManagedAsyncClientConnection connection = \
poolEntry.getConnection(); + final TimeValue timeValue \
= connectionConfig.getValidateAfterInactivity(); + if \
(connection.isOpen() && TimeValue.isNonNegative(timeValue)) { + \
final Deadline deadline = Deadline.calculate(poolEntry.getUpdated(), timeValue); + \
if (deadline.isExpired()) { + final \
ProtocolVersion protocolVersion = connection.getProtocolVersion(); + \
if (protocolVersion != null && protocolVersion.greaterEquals(HttpVersion.HTTP_2_0)) { \
+ connection.submitCommand(new \
PingCommand(new BasicPingHandler(result -> { + \
if (result == null || !result) { + \
if (LOG.isDebugEnabled()) { + \
LOG.debug("{} connection {} is stale", id, ConnPoolSupport.getId(connection)); + \
} + \
poolEntry.discardConnection(CloseMode.GRACEFUL); + \
} + leaseCompleted(poolEntry);
+ })), Command.Priority.IMMEDIATE);
+ return;
+ } else {
if (LOG.isDebugEnabled()) {
- LOG.debug("{} connection {} is \
stale", id, ConnPoolSupport.getId(connection)); + \
LOG.debug("{} connection {} is closed", id, ConnPoolSupport.getId(connection)); }
\
poolEntry.discardConnection(CloseMode.IMMEDIATE); }
- })), Command.Priority.IMMEDIATE);
- } else {
- if (LOG.isDebugEnabled()) {
- LOG.debug("{} connection {} is closed", id, \
ConnPoolSupport.getId(connection)); }
- \
poolEntry.discardConnection(CloseMode.IMMEDIATE); }
}
leaseCompleted(poolEntry);
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManagerBuilder.java \
b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManagerBuilder.java
index 941f412..302e5af 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManagerBuilder.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/nio/PoolingAsyncClientConnectionManagerBuilder.java
@@ -87,7 +87,6 @@ public class PoolingAsyncClientConnectionManagerBuilder {
private Resolver<HttpRoute, SocketConfig> socketConfigResolver;
private Resolver<HttpRoute, ConnectionConfig> connectionConfigResolver;
private Resolver<HttpHost, TlsConfig> tlsConfigResolver;
- private TimeValue timeToLive;
public static PoolingAsyncClientConnectionManagerBuilder create() {
return new PoolingAsyncClientConnectionManagerBuilder();
@@ -198,9 +197,14 @@ public class PoolingAsyncClientConnectionManagerBuilder {
/**
* Sets maximum time to live for persistent connections
+ *
+ * @deprecated Use {@link #setDefaultConnectionConfig(ConnectionConfig)}
*/
+ @Deprecated
public final PoolingAsyncClientConnectionManagerBuilder \
setConnectionTimeToLive(final TimeValue timeToLive) {
- this.timeToLive = timeToLive;
+ setDefaultConnectionConfig(ConnectionConfig.custom()
+ .setTimeToLive(timeToLive)
+ .build());
return this;
}
@@ -252,7 +256,7 @@ public class PoolingAsyncClientConnectionManagerBuilder {
.build(),
poolConcurrencyPolicy,
poolReusePolicy,
- timeToLive,
+ null,
schemePortResolver,
dnsResolver);
poolingmgr.setConnectionConfigResolver(connectionConfigResolver);
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic