Skip to content

Commit 2d70a39

Browse files
author
Kyrylo Stokoz
committed
Added an option for netty connection pool to limit the time when connection can be put back to pool.
In case of Amazon Cloud DNS records can change in seconds, and taking into account that AHC caches already resolved connection and never re-resolve DNS records if response if ok, introducing option to limit life for cached connection, to be able to gracefully route traffic to new host in case dns records changed.
1 parent 6075ac6 commit 2d70a39

File tree

2 files changed

+41
-0
lines changed

2 files changed

+41
-0
lines changed

api/src/main/java/com/ning/http/client/AsyncHttpClientConfig.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ public class AsyncHttpClientConfig {
108108
protected HostnameVerifier hostnameVerifier;
109109
protected int ioThreadMultiplier;
110110
protected boolean strict302Handling;
111+
protected int maxConnectionLifeTimeInMs;
111112

112113
protected AsyncHttpClientConfig() {
113114
}
@@ -119,6 +120,7 @@ private AsyncHttpClientConfig(int maxTotalConnections,
119120
int idleConnectionInPoolTimeoutInMs,
120121
int idleConnectionTimeoutInMs,
121122
int requestTimeoutInMs,
123+
int connectionMaxLifeTimeInMs,
122124
boolean redirectEnabled,
123125
int maxDefaultRedirects,
124126
boolean compressionEnabled,
@@ -150,6 +152,7 @@ private AsyncHttpClientConfig(int maxTotalConnections,
150152
this.idleConnectionInPoolTimeoutInMs = idleConnectionInPoolTimeoutInMs;
151153
this.idleConnectionTimeoutInMs = idleConnectionTimeoutInMs;
152154
this.requestTimeoutInMs = requestTimeoutInMs;
155+
this.maxConnectionLifeTimeInMs = connectionMaxLifeTimeInMs;
153156
this.redirectEnabled = redirectEnabled;
154157
this.maxDefaultRedirects = maxDefaultRedirects;
155158
this.compressionEnabled = compressionEnabled;
@@ -500,6 +503,15 @@ public boolean isStrict302Handling() {
500503
return strict302Handling;
501504
}
502505

506+
/**
507+
* Return the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} will keep connection in the pool, or -1 to keep connection while possible.
508+
*
509+
* @return the maximum time in millisecond an {@link com.ning.http.client.AsyncHttpClient} will keep connection in the pool, or -1 to keep connection while possible.
510+
*/
511+
public int getMaxConnectionLifeTimeInMs() {
512+
return maxConnectionLifeTimeInMs;
513+
}
514+
503515
/**
504516
* Builder for an {@link AsyncHttpClient}
505517
*/
@@ -511,6 +523,7 @@ public static class Builder {
511523
private int defaultIdleConnectionInPoolTimeoutInMs = Integer.getInteger(ASYNC_CLIENT + "defaultIdleConnectionInPoolTimeoutInMS", 60 * 1000);
512524
private int defaultIdleConnectionTimeoutInMs = Integer.getInteger(ASYNC_CLIENT + "defaultIdleConnectionTimeoutInMS", 60 * 1000);
513525
private int defaultRequestTimeoutInMs = Integer.getInteger(ASYNC_CLIENT + "defaultRequestTimeoutInMS", 60 * 1000);
526+
private int defaultMaxConnectionLifeTimeInMs = Integer.getInteger(ASYNC_CLIENT + "defaultMaxConnectionLifeTimeInMs", -1);
514527
private boolean redirectEnabled = Boolean.getBoolean(ASYNC_CLIENT + "defaultRedirectsEnabled");
515528
private int maxDefaultRedirects = Integer.getInteger(ASYNC_CLIENT + "defaultMaxRedirects", 5);
516529
private boolean compressionEnabled = Boolean.getBoolean(ASYNC_CLIENT + "compressionEnabled");
@@ -980,6 +993,17 @@ public Builder setStrict302Handling(final boolean strict302Handling) {
980993
return this;
981994
}
982995

996+
/**
997+
* Set the maximum time in millisecond connection can be added to the pool for further reuse
998+
*
999+
* @param maxConnectionLifeTimeInMs the maximum time in millisecond connection can be added to the pool for further reuse
1000+
* @return a {@link Builder}
1001+
*/
1002+
public Builder setMaxConnectionLifeTimeInMs(int maxConnectionLifeTimeInMs) {
1003+
this.defaultMaxConnectionLifeTimeInMs = maxConnectionLifeTimeInMs;
1004+
return this;
1005+
}
1006+
9831007
/**
9841008
* Create a config builder with values taken from the given prototype configuration.
9851009
*
@@ -993,6 +1017,7 @@ public Builder(AsyncHttpClientConfig prototype) {
9931017
defaultIdleConnectionInPoolTimeoutInMs = prototype.getIdleConnectionInPoolTimeoutInMs();
9941018
defaultIdleConnectionTimeoutInMs = prototype.getIdleConnectionTimeoutInMs();
9951019
defaultMaxConnectionPerHost = prototype.getMaxConnectionPerHost();
1020+
defaultMaxConnectionLifeTimeInMs = prototype.getMaxConnectionLifeTimeInMs();
9961021
maxDefaultRedirects = prototype.getMaxRedirects();
9971022
defaultMaxTotalConnections = prototype.getMaxTotalConnections();
9981023
proxyServer = prototype.getProxyServer();
@@ -1046,6 +1071,7 @@ public AsyncHttpClientConfig build() {
10461071
defaultIdleConnectionInPoolTimeoutInMs,
10471072
defaultIdleConnectionTimeoutInMs,
10481073
defaultRequestTimeoutInMs,
1074+
defaultMaxConnectionLifeTimeInMs,
10491075
redirectEnabled,
10501076
maxDefaultRedirects,
10511077
compressionEnabled,

providers/netty/src/main/java/com/ning/http/client/providers/netty/NettyConnectionsPool.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,21 @@ public class NettyConnectionsPool implements ConnectionsPool<String, Channel> {
3434
private final static Logger log = LoggerFactory.getLogger(NettyConnectionsPool.class);
3535
private final ConcurrentHashMap<String, ConcurrentLinkedQueue<IdleChannel>> connectionsPool = new ConcurrentHashMap<String, ConcurrentLinkedQueue<IdleChannel>>();
3636
private final ConcurrentHashMap<Channel, IdleChannel> channel2IdleChannel = new ConcurrentHashMap<Channel, IdleChannel>();
37+
private final ConcurrentHashMap<Channel, Long> channel2CreationDate = new ConcurrentHashMap<Channel, Long>();
3738
private final AtomicBoolean isClosed = new AtomicBoolean(false);
3839
private final Timer idleConnectionDetector = new Timer(true);
3940
private final boolean sslConnectionPoolEnabled;
4041
private final int maxTotalConnections;
4142
private final int maxConnectionPerHost;
43+
private final int maxConnectionLifeTimeInMs;
4244
private final long maxIdleTime;
4345

4446
public NettyConnectionsPool(NettyAsyncHttpProvider provider) {
4547
this.maxTotalConnections = provider.getConfig().getMaxTotalConnections();
4648
this.maxConnectionPerHost = provider.getConfig().getMaxConnectionPerHost();
4749
this.sslConnectionPoolEnabled = provider.getConfig().isSslConnectionPoolEnabled();
4850
this.maxIdleTime = provider.getConfig().getIdleConnectionInPoolTimeoutInMs();
51+
this.maxConnectionLifeTimeInMs = provider.getConfig().getMaxConnectionLifeTimeInMs();
4952
this.idleConnectionDetector.schedule(new IdleChannelDetector(), maxIdleTime, maxIdleTime);
5053
}
5154

@@ -145,6 +148,15 @@ public boolean offer(String uri, Channel channel) {
145148
return false;
146149
}
147150

151+
Long createTime = channel2CreationDate.get(channel);
152+
if (createTime == null){
153+
channel2CreationDate.putIfAbsent(channel, System.currentTimeMillis());
154+
}
155+
else if (maxConnectionLifeTimeInMs != -1 && (createTime + maxConnectionLifeTimeInMs) < System.currentTimeMillis() ) {
156+
log.debug("Channel {} expired", channel);
157+
return false;
158+
}
159+
148160
log.debug("Adding uri: {} for channel {}", uri, channel);
149161
channel.getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(new NettyAsyncHttpProvider.DiscardEvent());
150162

@@ -222,6 +234,7 @@ private boolean remove(IdleChannel pooledChannel) {
222234
* {@inheritDoc}
223235
*/
224236
public boolean removeAll(Channel channel) {
237+
channel2CreationDate.remove(channel);
225238
return !isClosed.get() && remove(channel2IdleChannel.get(channel));
226239
}
227240

@@ -251,11 +264,13 @@ public void destroy() {
251264
}
252265
connectionsPool.clear();
253266
channel2IdleChannel.clear();
267+
channel2CreationDate.clear();
254268
}
255269

256270
private void close(Channel channel) {
257271
try {
258272
channel.getPipeline().getContext(NettyAsyncHttpProvider.class).setAttachment(new NettyAsyncHttpProvider.DiscardEvent());
273+
channel2CreationDate.remove(channel);
259274
channel.close();
260275
} catch (Throwable t) {
261276
// noop

0 commit comments

Comments
 (0)