OkHttp: avoid leaked connection warning

Alphaaa picture Alphaaa · Jul 14, 2016 · Viewed 29k times · Source

I am using OkHttp 3, and I keep getting leaked connection warnings:

WARNING: A connection to https://help.helpling.com/ was leaked. Did you forget to close a response body?
Jul 14, 2016 6:57:09 PM okhttp3.ConnectionPool pruneAndGetAllocationCount

Everytime I get a ResponseBody, I either call .string() which supposedly closes the stream for me, or I explicitly close it in a finally block, in the following way:

ResponseBody responseBody = response.body();
try (Reader responseReader = responseBody.charStream()) {
    ...
}
finally {
    responseBody.close();
}

My application makes intense use of the network, and yet that warning appears frequently. I never observed any problem caused by this presumed leak, but I would still like to understand if and what I am doing wrong.

Could anyone shed some light on this?

Answer

Alphaaa picture Alphaaa · May 5, 2017

By upgrading to OkHttp 3.7, Eclipse started warning me of potential resource leaks. I found my problem to be in this method I wrote:

public static Response getResponse(HttpUrl url, OkHttpClient client) throws IOException {
    Builder request = new Request.Builder().url(url);
    Response response = client.newCall(request.build()).execute();
    if (!response.isSuccessful()) {
        boolean repeatRequest = handleHttpError(response);
        if (repeatRequest)
            return getResponse(url, client, etag);
        else
            throw new IOException(String.format("Cannot get successful response for url %s", url));
    }
    return response;
}

I assumed that by always calling getResponse(url, client).body().string() the stream would close automatically. But, whenever a response was unsuccessful, an exception would raise before the execution of .string(), thus the stream would remain open.

Adding an explicit close in case of unsuccessful response solved the problem.

if (!response.isSuccessful()) {
    boolean repeatRequest = handleHttpError(response);
    response.close();
}