Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to control the okHttpClient connections size?

I am debugging an issue in my android app. I found the root cause is file descriptors went beyond the limit. After further investigation I found that the app has too many sockets open. I use OkHttpClient 2.5 for all of my network communication, thus I am wondering how should I limit my connection pool size. Below is my code snippet:

    OkHttpClient okHttpClient = new OkHttpClient().setConnectTimeout(TIMEOUT);
    ConnectionPool connectionPool = new ConnectionPool(MAX_IDLE_CONNECTIONS,
                                                       KEEP_ALIVE_DURATION_MS);
    okHttpClient.set(connectionPool);

    @RequireArgsConstructor
    public HttpEngineCallable implements Callable<IHttpResponse>
    {
      private final String url;

      public IHttpResponse call () throws Exception 
      {
         try
        {
           Request request = Request.Builder().url(url).build();
           Call call = okHttpClient.newCall(request);
           Response rawResponse = call.execute();
           return new OkHttpResponse(rawResponse);
        }
        catch (Exception e)
        {
           throw new IllegalStateException(e);
        }
    }  

    private final Function<IHttpResponse, T> httpResponseParser = new Function<IHttpResponse, T>()
    {
        @Nullable
        @Override
        public T apply(@Nullable IHttpResponse httpResponse)
        {
            if(httpResponse == null)
            {
               return null;
            }

            InputStream stream = httpResponse.getBody();
            JsonParser parser = null;
            T result = null;

            try
            {
               parser = jsonFactory.createParser(stream);
               result = strategy.parseData(parser);
            }
            catch (Exception e)
            {
               log.error("Unable to convert {} with {}.", stream, strategy, e);
            }
            finally
            {
               IOUtils.closeQuietly(parser);
               IOUtils.closeQuietly(stream);
            } 

          return result;
        }
     };

     Future<T> future = executorService.submit(new HttpEngineCallable(url));
     Future<V> finalFuture = Futures.transform(future, httpResponseParser, executorService);

     T result = timeoutExecutorService.submit(new Runnable() 
     {
        try
        { 
          T result = finalFuture.get(CLIENT_TIMEOUT, TIMEUNIT)
          if (result == null)
          { 
            notify onFailure listeners
          }
          else
          {
            notify onSuccess Listeners
          }
        }
        catch(Exception ex)
        {
          notify onFailure listeners
        }
     } 

So I have a few questions regarding this implementation:

  1. My CLIENT_TIMEOUT is shorter than OkHttp ConnectTimeout. If my finalFuture.get(CLINT_TIMEOUT, TIMEUNIT) throws timeout exception, would my finally block in the Parser Function still be executed? I am counting on it to close my connection.
  2. How can limits the size of my ConnectionPool? Is there way I can auto-recycle oldest connections if connection went beyond limit?
like image 482
wish_me_luck7 Avatar asked Mar 04 '16 23:03

wish_me_luck7


1 Answers

We had a similar issue with too many open file descriptors crashing our app.

The problem was that we created one OkHttpClient per request. By default each OkHttpClient comes with its own connection pool, which of course blows up the number of connections/threads/file handles and prevents proper reuse in the pool.

We solved the problem by manually creating a global ConnectionPool in a singleton, and then passing that to the OkHttpClient.Builder object which builds the actual OkHttpClient.

...
builder.connectionPool(GLOBAL_CONNECTION_POOL);
OkHttpClient client = builder.build();
...

This still allows for per-request configuration using the OkHttpClient.Builder and makes sure all OkHttpClient instances are still using a common connection pool. We were then able to properly size the global connection pool.

like image 134
fgysin Avatar answered Oct 12 '22 23:10

fgysin