Skip to content

Commit ed98538

Browse files
committed
Merge pull request AsyncHttpClient#134 from kstokoz/master
An option to limit pooled connections life time
2 parents 0631899 + 2d70a39 commit ed98538

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)