title: How can I handle connection timeout and client timeout differently in retrofit with okhttp3
body: <p>I'm working on a instant message REST client library which communicate with a REST server belongs to 3rd party (there's no way I can touch the code or logic at server side) using retrofit v2.1.0.</p>
  
  <p>For some reason I keep receiving java.net.SocketTimeoutException when calling the interface synchronically.</p>
  
  <pre><code>java.net.SocketTimeoutException: timeout
      at okio.Okio$3.newTimeoutException(Okio.java:212) ~[okio-1.8.0.jar:?]
      at okio.AsyncTimeout.exit(AsyncTimeout.java:288) ~[okio-1.8.0.jar:?]
      at okio.AsyncTimeout$2.read(AsyncTimeout.java:242) ~[okio-1.8.0.jar:?]
      at okio.RealBufferedSource.indexOf(RealBufferedSource.java:325) ~[okio-1.8.0.jar:?]
      at okio.RealBufferedSource.indexOf(RealBufferedSource.java:314) ~[okio-1.8.0.jar:?]
      at okio.RealBufferedSource.readUtf8LineStrict(RealBufferedSource.java:210) ~[okio-1.8.0.jar:?]
      at okhttp3.internal.http.Http1xStream.readResponse(Http1xStream.java:184) ~[okhttp-3.3.0.jar:?]
      at okhttp3.internal.http.Http1xStream.readResponseHeaders(Http1xStream.java:125) ~[okhttp-3.3.0.jar:?]
      at okhttp3.internal.http.HttpEngine.readNetworkResponse(HttpEngine.java:775) ~[okhttp-3.3.0.jar:?]
      at okhttp3.internal.http.HttpEngine.access$200(HttpEngine.java:86) ~[okhttp-3.3.0.jar:?]
      at okhttp3.internal.http.HttpEngine$NetworkInterceptorChain.proceed(HttpEngine.java:760) ~[okhttp-3.3.0.jar:?]
      at okhttp3.internal.http.HttpEngine.readResponse(HttpEngine.java:613) ~[okhttp-3.3.0.jar:?]
      at okhttp3.RealCall.getResponse(RealCall.java:244) ~[okhttp-3.3.0.jar:?]
      at okhttp3.RealCall$ApplicationInterceptorChain.proceed(RealCall.java:201) ~[okhttp-3.3.0.jar:?]
      at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:163) ~[okhttp-3.3.0.jar:?]
      at okhttp3.RealCall.execute(RealCall.java:57) ~[okhttp-3.3.0.jar:?]
      at retrofit2.OkHttpCall.execute(OkHttpCall.java:174) ~[retrofit-2.1.0.jar:?]
  </code></pre>
  
  <p>By looking into the stack trace, I find out it's a client read timeout not a connection timeout, the server actually received my request, backend logic has been executed correctly, but my client failed to read the response from the server.</p>
  
  <p>If I keep retrying, the server will receive duplicate request which might lead to sending duplicate messages to another client. there's serious consequences if I drop the client read timeout exception, but as a library it would be better if I can notify the users of my library that this exception actually happened, and they can choose to ignore or take other necessary actions.</p>
  
  <p>If I swallow the SocketTimeoutException, and it is actually a connection timeout, the server might never received my request, I will lost a message from another client.</p>
  
  <p>Any idea how I can achieve the goal that determine the SocketTimeoutException I got is a client read timeout or a connection timeout, and only retry on connection timeout?</p>
  
  <p><strong>Update 1</strong></p>
  
  <p>The code I use to create okhttp client and retrofit service:</p>
  
  <pre><code>public SampleApi createSampleService() {
      OkHttpClient.Builder clientBuilder = new OkHttpClient().newBuilder()
              .retryOnConnectionFailure(true)
              .connectTimeout(30, TimeUnit.SECONDS)
              .writeTimeout(30, TimeUnit.SECONDS);
              .readTimeout(30, TimeUnit.SECONDS);
      return new Retrofit.Builder()
              .baseUrl(BASE_URL)
              .client(clientBuilder.build())
              .build()
              .create(SampleApi.class);
  }
  </code></pre>
  
  <p>I set retryOnConnectionFailure to true here, will this prevent throwing connection timeout error because it will keep retrying until the connection is successful, so the only timeout error I can possibly get is client read timeout? I wondering how many times it will retry and what happens after that.</p>