Le 18/09/2013 15:54, Oleg Kalnichevski a écrit :
On Wed, 2013-09-18 at 15:24 +0200, Boris Granveaud wrote:
Le 18/09/2013 13:23, Oleg Kalnichevski a écrit :
On Wed, 2013-09-18 at 11:39 +0200, Boris Granveaud wrote:
Hi,
I would like to automatically close persistent connections after some
time, *even if they are used* (but only at the end of a query of course).
I need this so that when I would like to deploy a new middle server, I
can remove it from the production pool of servers and wait for example
60 seconds that the front webapps close their persistent HttpClient
connections.
I have seen that you can set a timeToLive parameter in
PoolingHttpClientConnectionManager but this is used only to close idle
connections.
I cannot use ConnectionReuseStrategy and KeepAliveStrategy because I
don't have access to the connection that is used.
Finally, I tried to extend PoolingHttpClientConnectionManager to remove
the call to updateExpiry in releaseConnection:
public void releaseConnection(
final HttpClientConnection managedConn,
final Object state,
final long keepalive, final TimeUnit tunit) {
...
if (conn.isOpen()) {
entry.setState(state);
entry.updateExpiry(keepalive, tunit != null ? tunit
: TimeUnit.MILLISECONDS);
but this is not feasible as CPoolEntry and CPoolProxy which are used in
this method are not public classes.
Any idea?
Thanks,
Boris.
AbstractConnPool class, which CPool is based upon, provides #enumLeased
method that can be used to enumerate leased connections and optionally
close some or all of them. Truth to be told, I simply forgot to add a
corresponding method to PoolingHttpClientConnectionManager.
Please raise a change request in JIRA for this issue. For the time being
you will have to resort to reflection in order to get hold of the 'pool'
instance variable and cast it to AbstractConnPool.
I'm trying to implement your solution with a timer which periodically
enumerates leased connections and closes those which are too old, but
from time to time I have an exception like this:
Caused by: java.io.InterruptedIOException: Connection already shutdown
at
org.apache.http.impl.conn.DefaultManagedHttpClientConnection.bind(DefaultManagedHttpClientConnection.java:116)
~[httpclient-4.3.jar:4.3]
at
org.apache.http.impl.conn.HttpClientConnectionOperator.connect(HttpClientConnectionOperator.java:110)
~[httpclient-4.3.jar:4.3]
at
org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:314)
~[httpclient-4.3.jar:4.3]
at
org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:357)
~[httpclient-4.3.jar:4.3]
at
org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:218)
~[httpclient-4.3.jar:4.3]
at
org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:194)
~[httpclient-4.3.jar:4.3]
at
org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:186)
~[httpclient-4.3.jar:4.3]
at
org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
~[httpclient-4.3.jar:4.3]
at
org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:106)
~[httpclient-4.3.jar:4.3]
I suppose this is due to the fact that the connection is closed in
another thread. I do call CPoolEntry.shutdownConnection() instead of
CPoolEntry.closeConnection() but there must be a race condition somewhere.
You are basically shutting down the connection which is currently being
used to execute a request. This can cause all sorts of exceptions
depending on what stage execution process is at. InterruptedIOException
is perfectly legit in this context.
ok, I thought that shutdownConnection() was intended to mark that the
connection should be closed when released.
I'm not very comfortable with this solution because of these thread
synchronization issues. I also have to do the same on idle connections
and each enumeration, even if it is fast, locks the pool. It is a pity
that it is not possible to alter the behavior of
PoolingHttpClientConnectionManager.releaseConnection.
Here is my complete code if you see what's wrong:
There is probably nothing wrong with your code. If you intend to shut
down connections 'midair' so to speak, this is what you have to live
with. Changing #releaseConnection will not help given that time to live
and expiry attributes apply to idle connections only.
As far as I understand, #releaseConnection resets the connection expiry
date with the keepalive value because the connection has just been used.
So if I was able to remove this behavior, the connection will "expire"
for example 60 seconds after its creation even if it is intensively used.
Or I could let the keepalive and expiry management, and add something
like this:
public void releaseConnection(
(...)
if (conn.isOpen()) {
entry.setState(state);
entry.updateExpiry(keepalive, tunit != null ? tunit
: TimeUnit.MILLISECONDS);
if (System.currentTimeMillis() - entry.getCreated()
> maxAge) {
entry.closeConnection();
}
}
Maybe would it be interesting to make this maxAge parameter standard in
PoolingHttpClientConnectionManager. What do you think?
Boris.
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]