Skip to content
Permalink
Browse files
Blocking connection managers to validate connections after inactivity…
… of more than 2s by default; behavior of async connection managers remains the same
  • Loading branch information
ok2c committed Mar 16, 2021
1 parent 5875ca1 commit 10e2deb21007279720bd93c8c10c5af1b987b951
Showing 4 changed files with 53 additions and 5 deletions.
@@ -38,6 +38,7 @@
import org.apache.hc.client5.http.DnsResolver;
import org.apache.hc.client5.http.HttpRoute;
import org.apache.hc.client5.http.SchemePortResolver;
import org.apache.hc.client5.http.impl.ConnPoolSupport;
import org.apache.hc.client5.http.impl.ConnectionShutdownException;
import org.apache.hc.client5.http.io.ConnectionEndpoint;
import org.apache.hc.client5.http.io.HttpClientConnectionManager;
@@ -109,6 +110,8 @@ 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())
@@ -138,6 +141,7 @@ public BasicHttpClientConnectionManager(
this.expiry = Long.MAX_VALUE;
this.socketConfig = SocketConfig.DEFAULT;
this.closed = new AtomicBoolean(false);
this.validateAfterInactivity = TimeValue.ofSeconds(2L);
}

public BasicHttpClientConnectionManager(
@@ -228,6 +232,26 @@ private void checkExpiry() {
}
}

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 (stale) {
if (LOG.isDebugEnabled()) {
LOG.debug("{} connection {} is stale", id, ConnPoolSupport.getId(conn));
}
closeConnection(CloseMode.GRACEFUL);
}
}
}

synchronized ManagedHttpClientConnection getConnection(final HttpRoute route, final Object state) throws IOException {
Asserts.check(!this.closed.get(), "Connection manager has been shut down");
if (LOG.isDebugEnabled()) {
@@ -240,6 +264,7 @@ synchronized ManagedHttpClientConnection getConnection(final HttpRoute route, fi
this.route = route;
this.state = state;
checkExpiry();
validate();
if (this.conn == null) {
this.conn = this.connFactory.createConnection(null);
} else {
@@ -365,6 +390,27 @@ public synchronized void closeIdle(final TimeValue idleTime) {
}
}

/**
* @see #setValidateAfterInactivity(TimeValue)
*
* @since 5.1
*/
public TimeValue getValidateAfterInactivity() {
return validateAfterInactivity;
}

/**
* Defines period of inactivity after which persistent connections must
* be re-validated prior to being {@link #lease(String, HttpRoute, Object)} leased} to the consumer.
* Negative values passed to this method disable connection validation. This check helps
* detect connections that have become stale (half-closed) while kept inactive in the pool.
*
* @since 5.1
*/
public void setValidateAfterInactivity(final TimeValue validateAfterInactivity) {
this.validateAfterInactivity = validateAfterInactivity;
}

class InternalConnectionEndpoint extends ConnectionEndpoint {

private final HttpRoute route;
@@ -95,9 +95,6 @@
* Total time to live (TTL) set at construction time defines maximum life span
* of persistent connections regardless of their expiration setting. No persistent
* connection will be re-used past its TTL value.
* <p>
* Please note in contrast to 4.x no stale check is employed by default.
* @see #setValidateAfterInactivity(TimeValue)
*
* @since 4.3
*/
@@ -206,6 +203,7 @@ protected PoolingHttpClientConnectionManager(
}
this.connFactory = connFactory != null ? connFactory : ManagedHttpClientConnectionFactory.INSTANCE;
this.closed = new AtomicBoolean(false);
this.validateAfterInactivity = TimeValue.ofSeconds(2L);
}

@Internal
@@ -212,7 +212,9 @@ public PoolingHttpClientConnectionManager build() {
schemePortResolver,
dnsResolver,
connectionFactory);
poolingmgr.setValidateAfterInactivity(this.validateAfterInactivity);
if (validateAfterInactivity != null) {
poolingmgr.setValidateAfterInactivity(validateAfterInactivity);
}
if (defaultSocketConfig != null) {
poolingmgr.setDefaultSocketConfig(defaultSocketConfig);
}
@@ -201,7 +201,9 @@ public PoolingAsyncClientConnectionManager build() {
timeToLive,
schemePortResolver,
dnsResolver);
poolingmgr.setValidateAfterInactivity(this.validateAfterInactivity);
if (validateAfterInactivity != null) {
poolingmgr.setValidateAfterInactivity(validateAfterInactivity);
}
if (maxConnTotal > 0) {
poolingmgr.setMaxTotal(maxConnTotal);
}

0 comments on commit 10e2deb

Please sign in to comment.