We use Retrofit/OkHttp3 for all network traffic from our Android application. So far everything seems to run quite smoothly.
However, we have now occasionally had our app/process run out of file handles.
We were able to debug this exactly, where each dispached async call using
.enqueue()
will lead to an increase of open file handles of 3.
The problem is, that the ConnectionPool
in OkHttp seems to be keeping the connection threads around for much longer than they are actually needed. (This post talks of five minutes, though I haven't seen this specified anywhere.)
I've seen that it is possible to limit the number of parallel calls with Dispatcher.setMaxRequests()
(although it seems unclear whether this actually works, see here) - but that still doesn't quite address the issue with the open threads and file handles piling up.
How could we prevent OkHttp from creating too many file handles?
In software engineering, a connection pool is a cache of database connections maintained so that the connections can be reused when future requests to the database are required. Connection pools are used to enhance the performance of executing commands on a database.
If the maximum pool size has been reached and no usable connection is available, the request is queued. The pooler then tries to reclaim any connections until the time-out is reached (the default is 15 seconds). If the pooler cannot satisfy the request before the connection times out, an exception is thrown.
Click Resources > JDBC > Data Sources > data_source > [Additional Properties] Connection pool properties. Click Resources > JMS->Queue connection factories-> queue_connection_factory ->[Additional Properties] Connection pool.
For optimal performance, use a pool with eight to 16 connections per node. For example, if you have four nodes configured, then the steady-pool size must be set to 32 and the maximum pool size must be 64.
I am answering my own question here to document this issue we had. It took us a while to figure this out and I think others might encounter this too and might be glad for this answer.
Our problem was that we created one OkHttpClient
per request, as we used it's builder/interceptor API to configure some per-request parameters like HTTP headers or timeouts.
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
.
OkHttpClient.Builder
OkHttpClient
instances are still using a common connection pool.We were then able to properly size the global connection pool.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With