10

Here's my configuration:

httpClient = new OkHttpClient.Builder()
        .callTimeout(Duration.ofSeconds(60))
        .connectTimeout(Duration.ofSeconds(60))
        .readTimeout(Duration.ofSeconds(60))
        .writeTimeout(Duration.ofSeconds(60))
        .build();

I have a multithreaded process that uses this client. Few seconds after running I'm getting:

java.net.SocketTimeoutException: timeout
at okio.Okio$4.newTimeoutException(Okio.java:232)
at okio.AsyncTimeout.exit(AsyncTimeout.java:286)
at okio.AsyncTimeout$2.read(AsyncTimeout.java:241)
at okio.RealBufferedSource.indexOf(RealBufferedSource.java:358)

How is it possible if I configured the timeouts to 60 seconds?

EDIT:
Even adding a custom dispatcher didn't help:

Dispatcher dispatcher = new Dispatcher();
dispatcher.setMaxRequests(Integer.MAX_VALUE);
dispatcher.setMaxRequestsPerHost(Integer.MAX_VALUE);

TECHNICAL DETAILS:
As opposed to what I've said, I'm running both the client and the server on Linux machines:

Client's machine: net.ipv4.tcp_keepalive_time = 7200
Server's machine: net.ipv4.tcp_keepalive_time = 7200

IsaacLevon
  • 2,260
  • 4
  • 41
  • 83
  • Possible duplicate of [Getting java.net.SocketTimeoutException: Connection timed out in android](https://stackoverflow.com/questions/15608499/getting-java-net-sockettimeoutexception-connection-timed-out-in-android) – Michiel Leegwater Aug 08 '19 at 14:13
  • 1
    @MichielLeegwater, it's not duplicate and anyhow the linked SO post doesn't offer a reasonable solution – IsaacLevon Aug 09 '19 at 08:00
  • have you considered the possibility that the server has a very small timeout and that it has nothing to do with your code ? – a_local_nobody Aug 11 '19 at 10:08
  • https://stackoverflow.com/questions/18184899/what-is-the-difference-between-the-setconnectiontimeout-setsotimeout-and-http you may want to see this – Sarel Foyerlicht Aug 11 '19 at 10:09
  • @a_local_nobody, I actually have considered this option but I thought (maybe falsely) that timeout exception can happen only from client side. I'm using a vanilla Flask server so that might be it - If you want to collect the bounty please write it as an answer – IsaacLevon Aug 11 '19 at 10:12
  • no, you're establishing a session between yourself and the server, so it's entirely possible the server kicks you out – a_local_nobody Aug 11 '19 at 10:14
  • Yeah, I agree. I think that I imagined that there's another unique exception for server's timeout (something like Connection Refused or whatever) – IsaacLevon Aug 11 '19 at 10:15
  • The difference is that you'd get an http response 408, otherwise all the client could say is "connection closed". Might be worth logging or sniffing packets to check whether it's that – Aaron Aug 11 '19 at 10:17
  • Because you set a 60s read timeout and it expired. The peer didn't respond within 60 seconds. Either your timeout is too short (unlikely with this value) or there is something wrong wth the server, – user207421 Aug 11 '19 at 10:19
  • @user207421, it can't be client side as I explained - since the application ran for only few seconds – IsaacLevon Aug 11 '19 at 10:57
  • Are you on Linux, iOS, Android or Windows? Did you change the default system settings for the network? And what exactly is "few seconds"? – Karol Dowbecki Aug 11 '19 at 11:43
  • client - MacOS, Server - Flask on Ubuntu. Few seconds is literally few seconds (let's say 5) – IsaacLevon Aug 11 '19 at 11:50
  • Show the output of `sysctl net.inet.tcp` on Mac, I'm assuming that's where your code is getting a timeout exception. If not please clarify what's the server doing (Isn't Flask a Python thing?). – Karol Dowbecki Aug 11 '19 at 11:53
  • Do you know from logs as to how much time is this timeout? Like 30 sec or even lesser? Also which server does this client connects to? – Tarun Lalwani Aug 11 '19 at 16:21
  • @yaseco, please add more code related to how your thread makes call – Sahil Manchanda Aug 13 '19 at 14:43
  • 1
    This is fixed in okhttps 4.3. See https://github.com/square/okhttp/issues/3146#issuecomment-569986444 – Jose Jan 11 '20 at 16:21

2 Answers2

5

You are most likely affected by the socket timeouts imposed by the operating system. Java can't extend them since the sockets are managed by the system. As per this great answer, "Changing TCP Timeouts" section:

Unfortunately since TCP connections are managed on the OS level, Java does not support configuring timeouts on a per-socket level such as in java.net.Socket. I have found some attempts to use Java Native Interface (JNI) to create Java sockets that call native code to configure these options, but none appear to have widespread community adoption or support.

For MacOS you have to look at sysctl net.inet.tcp output and see what are the system limits.

Karol Dowbecki
  • 43,645
  • 9
  • 78
  • 111
  • Thanks Karol (I guess that same command applies for Linux, right?) – IsaacLevon Aug 11 '19 at 12:16
  • So to sum up, defining timeouts on application-level (in Java) is meaningless as the socket timeouts are defined on the OS level. – IsaacLevon Aug 11 '19 at 12:17
  • On my linux machine I see: net.ipv4.tcp_keepalive_time = 7200 – IsaacLevon Aug 11 '19 at 12:21
  • You can decrease the timeout limit in Java but you can't increase it past the OS timeout limit. At this point I don't understand if you are getting this timeout on MacOS or Linux, the limits are OS dependent. Rewrite your question to clearly specify the OS and code that causes the problem, right now it's hard to understand. – Karol Dowbecki Aug 11 '19 at 12:27
2

I think the issue is somewhere else. The timeout does work. I tried the following on my machine and it worked for 30 seconds

package test;

import java.io.IOException;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

/**
 *
 * @author jingged
 */
public class Test {
OkHttpClient httpClient = null;
     void initClient(){
        httpClient = new OkHttpClient.Builder()
        .connectTimeout(30, TimeUnit.SECONDS)
        .readTimeout(30, TimeUnit.SECONDS)
        .writeTimeout(30, TimeUnit.SECONDS)
        .build();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Test test = new Test();
        test.initClient();
        for(int i = 0;i<10;i++){
            new Thread(new Runnable(){
                @Override
                public void run() {
                   Request request = new Request.Builder().url("https://10.255.255.1").build();
                   Instant start = Instant.now();
                   try (Response response = test.httpClient.newCall(request).execute()) {
                        String s =  response.body().string();
                        System.out.println(s);
                    } catch (IOException ex) {
                        if (ex instanceof java.net.SocketTimeoutException){
                            System.err.print("Socket TimeOut");
                        }else{
                            ex.printStackTrace();
                        }
                    }
                   Instant end = Instant.now();
                    Duration interval = Duration.between(start, end);
                    System.out.println("Execution time " + interval.getSeconds()+" seconds");
                }

            }).start();
        }
    }
}

Output:

Execution time 30 seconds
Execution time 30 seconds
Execution time 30 seconds
Execution time 30 seconds
Execution time 30 seconds
Execution time 30 seconds
Execution time 30 seconds
Execution time 30 seconds
Execution time 30 seconds
Execution time 30 seconds
Socket TimeOutSocket TimeOutSocket TimeOutSocket TimeOutSocket TimeOutSocket TimeOutSocket TimeOutSocket TimeOutSocket TimeOutSocket TimeOut
BUILD SUCCESSFUL (total time: 32 seconds)

Try the above code. the url mentioned in the above code will produce TimeOut exception as it doesn't exists but the timeout time should keep it going for 30 seconds. BTW I tested this on MAC OS High Sierra with Java 8 and netbeans 8.2 with okhttp3

Sahil Manchanda
  • 9,812
  • 4
  • 39
  • 89