You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@hc.apache.org by Niranjan Kundapur <ni...@air2web.com> on 2003/04/23 16:40:32 UTC

MultiThreadedHttpConnectionManager and CLOSE_WAIT

Hello,

I am new user of HTTPClient. What I like about it is that it has a
MultiThreadedHttpConnectionManager. However, I am not sure if I am using it
in the correct way (Code included below). There is a static instance of
HttpClient, which is created with a MultiThreadedHttpConnectionManager. The
HttpClient instance is shared by multiple threads. 
The problem I see is a broken pipe exception when the following steps occur:
         1. Some requests have gone through. Connections are being reused.
         2. After a period of inactivity, connections are in CLOSE_WAIT on
the client side and FIN_WAIT on the server side. 
         3. Another request(s) comes in. 
         4. The connection pool does not know that the underlying connection
is in CLOSE_WAIT and tries to reuse it.
         5. Broken pipe exception occurs.
Work around: Test if exception is broken pipe and retry immediately. Retry
for a max number of times so that there is no infinite loop.

Questions:
----------
1) Is this usage of HttpClient correct?
2) Is there some way for the connection pool to know that the connection is
not usable? I read some other mails that seem to suggest that I need to wait
for a redesign. Is this available?
3) When I do netstat, I see lot of connections to the server in CLOSE_WAIT
state. These were used by HttpClient previously and then were timed out by
the server. Is the HttpClient not closing sockets explicitly whenever it
knows that a connection is in CLOSE_WAIT? Or is my usage incorrect?

Thanks,
Niranjan

---------------------

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

public class HTTPHelper2 
{
    private static final Logger LOG =
LogManager.getLogger(HTTPHelper2.class);
    private static final String
PROPERTY_httpHelper_maxConnectionsPerHost="httpHelper.maxConnectionsPerHost"
;
    private static final String
PROPERTY_httpHelper_numRetriesUponBrokenPipe="httpHelper.numRetriesUponBroke
nPipe";
    private static final String
PROPERTY_httpHelper_brokenPipeExceptionMsgFragment="httpHelper.brokenPipeExc
eptionMsgFragment";

    static private HttpConnectionManager HTTP_CONN_MGR =
initHttpConnectionManager();
    static private HttpClient HTTP_CLIENT = initHttpClient();

    public static byte[] connectToURL(String theUrlString, boolean
connectViaPost) throws Exception
    {
        int
numRetriesUponBrokenPipe=getIntProperty(PROPERTY_httpHelper_numRetriesUponBr
okenPipe);
        String
brokenPipeExceptionMsg=getProperty(PROPERTY_httpHelper_brokenPipeExceptionMs
gFragment,"broken pipe");
        for (int i=0; i<numRetriesUponBrokenPipe; i++)
        {
            if (i>0)
            {
                LOG.debug("Retrying connection to ["+theUrlString+"] upon
broken pipe. i="+i);
            }
            try
            {
                return _connectToURL(theUrlString, connectViaPost);
            }
            catch(Exception e)
            {
                if (e.getMessage()!=null &&
e.getMessage().toLowerCase().indexOf(brokenPipeExceptionMsg)==-1 )
                {
                    LOG.error("HTTPHelper2.connectToURL: Error occurred and
fyi i="+i, e);
                    throw e;
                }
            }
        } //for
        throw new Exception("HTTPHelper2.connectToURL: Exceeded the maximum
number of retries, which is ["+numRetriesUponBrokenPipe+"],  upon broken
pipe.");
    }

    static private byte[] _connectToURL(String theUrlString, boolean
connectViaPost) throws Exception
    {
        HttpClient httpClient = getHttpClient();
        GetMethod method = null;
        try
        {

            method = new GetMethod(theUrlString);

            httpClient.executeMethod(method);

            byte[] bytes = method.getResponseBody();

            return bytes;
        }
        catch (Exception e)
        {
            throw e;
        }
        finally
        {
            // always release the connection after we're done 
            method.releaseConnection();
            LOG.debug(" - connection released");
        }
    }

    static private HttpClient getHttpClient()
    {
        return HTTP_CLIENT;
    }

    static private HttpConnectionManager initHttpConnectionManager()
    {
        MultiThreadedHttpConnectionManager conMgr=new
MultiThreadedHttpConnectionManager();
 
conMgr.setMaxConnectionsPerHost(getIntProperty(PROPERTY_httpHelper_maxConnec
tionsPerHost));  //default is 2 as per RFC 2616 section 8.1.4
        return conMgr;
    }

    static private HttpClient initHttpClient()
    {
        return new HttpClient(HTTP_CONN_MGR);
    }
}




Re: MultiThreadedHttpConnectionManager and CLOSE_WAIT

Posted by Michael Becke <be...@u.washington.edu>.
Hi Niranjan,

This problem should be cleared up with the latest nightly build of 
HttpClient.  Quite a bit of work has been put in recently to fix 
problems with connection timeout and host management.

> Questions:
> ----------
> 1) Is this usage of HttpClient correct?

Yes, what you are doing is fine.

> 2) Is there some way for the connection pool to know that the connection is
> not usable? I read some other mails that seem to suggest that I need to wait
> for a redesign. Is this available?

As previously mentioned, this has recently been fixed.  Connection are 
now tested before reuse and re-opened when necessary.

> 3) When I do netstat, I see lot of connections to the server in CLOSE_WAIT
> state. These were used by HttpClient previously and then were timed out by
> the server. Is the HttpClient not closing sockets explicitly whenever it
> knows that a connection is in CLOSE_WAIT? Or is my usage incorrect?

The connections are being closed, but something about the underlying 
socket implementation keeps the connection open for a period of time. 
Take a look at:

http://www.developerweb.net/sock-faq/flatfaq.php
and
http://www.developerweb.net/sock-faq/detail.php?id=13

Mike