7

I keep getting a java.net.SocketTimeoutException when attempting an OkHttp3 asynchronous Get. This suggests that I haven't set the read timeout value high enough (I think the default is 10 seconds).

The larger question is "How to prevent this exception?" but, unless someone has a better initial strategy, my immediate question is, "How to set a read timeout value for the request?"

In my code I've used the information from the Okttp Recipes page here

Notice the first two lines of my try-catch are commented out. That's because I cannot use the kind of builder (one capable of setting a timeout value, OkHttpClient.Builder) that I need in order to add header info (Request.Builder) .

My code looks like this:

    m_client = new OkHttpClient();


    try
    {
        //OkHttpClient.Builder bldr = m_client.newBuilder();
        //bldr.readTimeout(0, TimeUnit.SECONDS);

        Request.Builder reqBuilder = new Request.Builder();

        reqBuilder.addHeader("authorization", getToken());

        Request request = reqBuilder.url("http://plusdev.kooklah.com/api/v2_1/items/get").build();

        m_client.newCall(request).enqueue(new Callback()
        {
            @Override
            public void onFailure(Call call, IOException e)
            {
                Log.i("Logit", "Inside onFailure() -- IOException: " + e.getMessage() + " ----- stack trace: " + UtilGen.exceptionToString(e));

                runOnUiThread(new Runnable()
                {
                    @Override
                    public void run()
                    {
                       // do stuff on UI thread
                    }
                });
            }

            @Override
            public void onResponse(Call call, final Response responseIn)
            {
                try
                {
                    m_sServerResponse = responseIn.body().string();
                }
                catch (Exception ex)
                {
                    Log.i("LogIt", "          ---Inside onResponse() -- Exception occurred. ex: " + ex.toString());
                }

                runOnUiThread(new Runnable()
                {
                    @Override
                    public void run()
                    {
                        Log.i("LogIt", "          ---Inside onResponse() -- inside run().");
                        if (!m_sServerResponse.isEmpty())
                        {
                            Log.i("LogIt", "          ---Inside onResponse() -- inside run() -- Success");
                            processDownloadedAssessments(m_sServerResponse);
                        }
                    }
                });
            }
        });
    }
    catch (Exception ex)
    {
        Log.i("LogIt", "ex: " + ex.getMessage());
    }

I found a reported issue that seems directly related, here, on the okhttp github site. There's even a recommendation to set the read timeout, which as mentioned above has been commented out because I cannot figure how to bring that kind of builder to bear on an async request as described on the Recipe page.

The stack trace for my exception is below, but be aware that most of the time I don't get the exception. Stack trace:

01-19 14:04:52.192: I/LogIt(25650): Inside onFailure() -- IOException: null ----- stack trace: java.net.SocketTimeoutException
01-19 14:04:52.192: I/LogIt(25650):     at java.net.PlainSocketImpl.read(PlainSocketImpl.java:488)
01-19 14:04:52.192: I/LogIt(25650):     at java.net.PlainSocketImpl.access$000(PlainSocketImpl.java:37)
01-19 14:04:52.192: I/LogIt(25650):     at java.net.PlainSocketImpl$PlainSocketInputStream.read(PlainSocketImpl.java:237)
01-19 14:04:52.192: I/LogIt(25650):     at okio.Okio$2.read(Okio.java:138)
01-19 14:04:52.192: I/LogIt(25650):     at okio.AsyncTimeout$2.read(AsyncTimeout.java:236)
01-19 14:04:52.192: I/LogIt(25650):     at okio.RealBufferedSource.indexOf(RealBufferedSource.java:325)
01-19 14:04:52.192: I/LogIt(25650):     at okio.RealBufferedSource.indexOf(RealBufferedSource.java:314)
01-19 14:04:52.192: I/LogIt(25650):     at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:210)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http1.Http1Codec.readResponse(Http1Codec.java:191)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http1.Http1Codec.readResponseHeaders(Http1Codec.java:132)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:54)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:120)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:92)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:67)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:179)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.RealCall$AsyncCall.execute(RealCall.java:129)
01-19 14:04:52.192: I/LogIt(25650):     at okhttp3.internal.NamedRunnable.run(NamedRunnable.java:32)
01-19 14:04:52.192: I/LogIt(25650):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
01-19 14:04:52.192: I/LogIt(25650):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
01-19 14:04:52.192: I/LogIt(25650):     at java.lang.Thread.run(Thread.java:818)
Alyoshak
  • 2,696
  • 10
  • 43
  • 70
  • The `OkHttpClient` builder and the `Request` builder are two different classes. You set the timeout in the `OkHttpClient` builder and it applies to ALL request. You set headers to the `Request` builder for individual requests. – LordRaydenMK Jan 19 '17 at 19:28
  • Very true, but how to bring the former into the request after having set its timeout value(s)? – Alyoshak Jan 19 '17 at 19:40
  • you execute the `Request` using the `OkHttpClient` built using the builder with the specified timeout. – LordRaydenMK Jan 19 '17 at 19:44
  • @LordRaydenMK -- As mentioned in the question the Request.Builder class is required in the async call, not the OkHttpClient.Builder. – Alyoshak Jan 19 '17 at 19:50
  • I have the same problem in kotlin. Can anyone help to resolve? – tinto mathew Dec 09 '19 at 12:03

1 Answers1

19

Instead of

m_client = new OkHttpClient();

you should create the client using a builder like:

m_client = new OkHttpClient.Builder()
        .connectTimeout(10, TimeUnit.SECONDS)
        .writeTimeout(10, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .build();

When you create the client like this each Request executed whit this client (using m_client.newCall(...)) will use the timeouts specified in the builder.

LordRaydenMK
  • 13,074
  • 5
  • 50
  • 56