[ 
https://issues.apache.org/jira/browse/HTTPCLIENT-1263?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13503103#comment-13503103
 ] 

Bryant Harris commented on HTTPCLIENT-1263:
-------------------------------------------

Sure, Here's a simple example to demonstrate, complied using 4.2.1 jars




package sample;

import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DecompressingHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.client.cache.CacheConfig;
import org.apache.http.impl.client.cache.CachingHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.util.EntityUtils;

/**
 * Simple test to demonstrate hanging issue when using a pooling http client.
 * 
 * Test creates 3 reader threads sharing a single HttpClient. performing reads
 * across 3 different domains.
 * 
 * Each thread properly consumes its content.
 * 
 * When using a caching client (useCachingClient = true) it will hang.  When
 * using standard client (useCachingClient = false) it works as expected
 * @author bryant_harris
 *
 */
public class HttpClient1263 {
        /** Set this value true demonstrates the bug, setting it to false shows 
that bypassing caching works as expected */
        static boolean useCachingClient = false;
        
        static HttpClient standardClient = null;
        static HttpClient cachedClient = null;
        static PoolingClientConnectionManager connectionManager = null;
        
        /**
         * Standard client, small number of connections, wrapped in a 
DecompressingHttpClient.
         * @return
         */
        protected static synchronized HttpClient getStandardClient() {
                if ( standardClient == null ) {
                        connectionManager = new 
PoolingClientConnectionManager();
                        connectionManager.setMaxTotal(2);
                        connectionManager.closeIdleConnections(120, 
TimeUnit.SECONDS);
                        standardClient = new DecompressingHttpClient( new 
DefaultHttpClient (connectionManager));
             }
                return standardClient;
        }
        
        /**
         * Wrapping standard client in pool, to expose the issue, using very 
small
         * cache to force network loads.
         * @return
         */
        protected static synchronized HttpClient getCachedClient() {
                if ( cachedClient == null ) {
                        CacheConfig cacheConfig = new CacheConfig();
                        cacheConfig.setMaxObjectSize( 512*1024 );
                        cacheConfig.setMaxCacheEntries( 1 );
                        cachedClient = new 
CachingHttpClient(getStandardClient(),
                                                                                
                 cacheConfig);
                }
                
                return cachedClient;
        }
        
        static Timer timer;

        /**
         * @param args
         */
        public static void main(String[] args) throws Exception {
                timer = new Timer("Hang detecting Timer",  true);

                // create some concurrent readers that will hit different 
domains.
                HttpReaderThread t1 = new 
HttpReaderThread("http://www.apple.com";);
                HttpReaderThread t2 = new 
HttpReaderThread("http://www.google.com";);
                HttpReaderThread t3 = new 
HttpReaderThread("http://www.yahoo.com";);
                
                t1.start();
                t2.start();
                t3.start();
        }

        static Random random = new Random(System.currentTimeMillis());
        static class HttpReaderThread extends Thread {
                String url;
                TimerTask hungTimer;
                
                public HttpReaderThread(String theUrl) {
                        url = theUrl;
                }
                
                public void run() {
                        for ( int i=0; i<20; i++ ) {
                                try {
                                        HttpGet method = new HttpGet(url);
                                        
                                        // Use client to read a request
                                        HttpClient client = useCachingClient ? 
getCachedClient() : getStandardClient();
                                        HttpResponse response = 
client.execute(method);
                                        HttpEntity entity = 
response.getEntity();
                                        EntityUtils.consume(entity);
                                        
                                        Thread.sleep(Math.abs(random.nextLong() 
% 100));
                                        
                                        // resetting a hung timer that will 
fire if we dont' complete
                                        // a read in a reasonable amount of 
time.
                                        if ( hungTimer != null )
                                                hungTimer.cancel();
                                        hungTimer = new TimerTask() {
                                                public void run() {
                                                        System.err.println(url 
+ " Thread is hung");
                                                }
                                        };
                                        timer.schedule(hungTimer, 5000);
                                }
                                catch (Exception e) {
                                        e.printStackTrace();
                                }
                        }
                        
                        if ( hungTimer != null )
                                hungTimer.cancel();
                        System.out.println(url + " Thread completed.");
                }
        }
}

                
> CachingHttpClient not consuming backend HttpResponse entity causing 
> PoolingClientConnectionManager to become unresponsive
> -------------------------------------------------------------------------------------------------------------------------
>
>                 Key: HTTPCLIENT-1263
>                 URL: https://issues.apache.org/jira/browse/HTTPCLIENT-1263
>             Project: HttpComponents HttpClient
>          Issue Type: Bug
>          Components: HttpClient
>    Affects Versions: 4.2.1
>            Reporter: Bryant Harris
>              Labels: cache, connection-pooling, consumed
>
> I've noticed that when issuing requests via a pooled and cached HttpClient 
> that the client eventually becomes unresponsive (which appears to be because 
> an HttpEntity is not getting consumed properly).
> Steps to reproduce.
> 1. Here is how I've configured all the relevant classes.
>     HttpClient standardClient = null;
>     HttpClient cachedClient = null;
>     PoolingClientConnectionManager connectionManager = null;
>     protected synchronized HttpClient getStandardClient() {
>       if ( standardClient == null ) {
>         connectionManager = new PoolingClientConnectionManager();
>         connectionManager.setMaxTotal(2);
>         connectionManager.closeIdleConnections(120, TimeUnit.SECONDS);
>         standardClient = new DecompressingHttpClient( new DefaultHttpClient 
> (connectionManager));
>       }
>       return standardClient;
>     }
> protected synchronized HttpClient getCachedClient() {
>   if ( cachedClient == null ) {
>     CacheConfig cacheConfig = new CacheConfig();
>     cacheConfig.setMaxObjectSize( 512*1024 );
>     cacheConfig.setMaxCacheEntries( 10 );
>     cachedClient = new CachingHttpClient(getStandardClient(),
>                                          getCacheStorage(),
>                                          cacheConfig);
>   }
>   return cachedClient;
> }
> As you can see I have two http clients. A caching http client that wraps the 
> standard client.
> Now what I've found is that if I remove cachedClient and only use 
> standardClient, I don't have any issues with the pool hanging and orphaned 
> connections.
> 2.  Here is my code for how I issue and consume requests
>     HttpClient httpClient = cacheOkay ? getCachedClient() : 
> getStandardClient();  
>     HttpResponse response = httpClient.execute(request, localContext);
>     HttpEntity resEntity = response.getEntity();  
>     int responseStatus = response.getStatusLine().getStatusCode();
>     byte[] responseBody = EntityUtils.toByteArray(resEntity);
>     EntityUtils.consume(resEntity);
> If you set up a test like this and use the cached client, it will hang fairly 
> quickly.
> I've been able to work around this by creating the CachingHttpClient as 
> follows:
>     protected synchronized HttpClient getCachedClient() {
>       if ( cachedClient == null ) {
>               WhosHereApplication application = 
> WhosHereApplication.getInstance();
>               cachedClient = new CachingHttpClient(getStandardClient(),
>                                                                               
>          new HeapResourceFactory() {
>                                                                               
>                         @Override
>                                                                               
>                         public Resource generate(
>                                                                               
>                                         String requestId,
>                                                                               
>                                         InputStream instream,
>                                                                               
>                                         InputLimit limit)
>                                                                               
>                                         throws IOException {
>                                                                               
>                                 try {
>                                                                               
>                                         return super.generate(requestId, 
> instream, limit);
>                                                                               
>                                 }
>                                                                               
>                                 finally {
>                                                                               
>                                         instream.close();
>                                                                               
>                                 }
>                                                                               
>                         }
>                       
>                                                                               
>          },
>                                                            
> application.getCacheStorage(),
>                                                            
> application.getCacheConfig());
>               Log.i(tag, "Creating CachingHttpClient");
>       }
>               
>       return cachedClient;
>     }
> Notice the inline subclass of HeapResourceFactory where I add the stream 
> close call.  Once I add this the caching client no longer freezes up.
> I'm not familiar enough with the source code to pinpoint the issue, but 
> appears the back end entity is not getting consumed properly, forcing this 
> work around.

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to