Analyzing OkHttp Timeout Mechanisms and Retrofit Request Handling

This article investigates why OkHttp timeouts appear ineffective in a Retrofit‑RxJava network stack, examines the internal flow of connectTimeout, readTimeout and writeTimeout through StreamAllocation, AsyncTimeout, and the Watchdog thread, and proposes configuration adjustments to avoid request stalls.

Xueersi Online School Tech Team
Xueersi Online School Tech Team
Xueersi Online School Tech Team
Analyzing OkHttp Timeout Mechanisms and Retrofit Request Handling

Introduction

Recent observations of occasional long‑lasting loads despite a 30‑second timeout setting prompted an in‑depth analysis of the OkHttp timeout configuration and its interaction with Retrofit and RxJava.

Problem Analysis

The business layer defines three timeout values (connect, read, write) all set to 30 s. Their meanings are:

connectTimeout – socket connection establishment timeout

readTimeout – timeout for reading server responses

writeTimeout – timeout for sending client data (e.g., uploads)

if (okConfig.getConnectTimeOut() > 0) {</code><code>    okBuilder.connectTimeout(okConfig.getConnectTimeOut(), TimeUnit.SECONDS);</code><code>} else {</code><code>    throw new IllegalArgumentException("connectTimeOut must be greater than 0");</code><code>}</code><code></code><code>if (okConfig.getWriteTimeOut() > 0) {</code><code>    okBuilder.writeTimeout(okConfig.getWriteTimeOut(), TimeUnit.SECONDS);</code><code>} else {</code><code>    throw new IllegalArgumentException("writeTimeout must be greater than 0");</code><code>}</code><code></code><code>if (okConfig.getReadTimeOut() > 0) {</code><code>    okBuilder.readTimeout(okConfig.getReadTimeOut(), TimeUnit.SECONDS);</code><code>} else {</code><code>    throw new IllegalArgumentException("readTimeout must be greater than 0");</code><code>}

Source Code Flow – connectTimeout

In StreamAllocation.newStream() the timeout values are retrieved from the interceptor chain and passed to findHealthyConnection(), which eventually calls RealConnection.connectSocket() where the socket connection timeout is applied.

public HttpCodec newStream(OkHttpClient client, Interceptor.Chain chain, boolean doExtensiveHealthChecks) {</code><code>    int connectTimeout = chain.connectTimeoutMillis();</code><code>    int readTimeout = chain.readTimeoutMillis();</code><code>    int writeTimeout = chain.writeTimeoutMillis();</code><code>    // ...</code><code>    RealConnection resultConnection = findHealthyConnection(connectTimeout, readTimeout, writeTimeout, ...);</code><code>    // ...</code><code>}

The connectSocket implementation on Android ultimately invokes socket.connect(address, connectTimeout), directly using the configured value.

public void connectSocket(Socket socket, InetSocketAddress address, int connectTimeout) throws IOException {</code><code>    try {</code><code>        socket.connect(address, connectTimeout);</code><code>    } catch (AssertionError e) {</code><code>        if (Util.isAndroidGetsocknameError(e)) throw new IOException(e);</code><code>        throw e;</code><code>    } catch (SecurityException e) {</code><code>        IOException ioException = new IOException("Exception in connect");</code><code>        ioException.initCause(e);</code><code>        throw ioException;</code><code>    } // ...</code><code>}

Source Code Flow – readTimeout

During Http1Codec creation, the read timeout is set on the raw socket and on the source/sink objects:

socket.setSoTimeout(readTimeout);</code><code>source.timeout().timeout(chain.readTimeoutMillis(), MILLISECONDS);</code><code>sink.timeout().timeout(chain.writeTimeoutMillis(), MILLISECONDS);

The Source implementation reads from the input stream and checks the timeout before each read via timeout.throwIfReached().

public long read(Buffer sink, long byteCount) throws IOException {</code><code>    timeout.throwIfReached();</code><code>    // read from InputStream...</code><code>}

AsyncTimeout and Watchdog

Both Source and Sink rely on AsyncTimeout, which maintains a sorted linked list of timeout nodes and a daemon Watchdog thread that wakes up when the head node expires, then calls timedOut() (typically closing the socket).

private static synchronized void scheduleTimeout(AsyncTimeout node, long timeoutNanos, boolean hasDeadline) {</code><code>    // Insert node in order, start Watchdog if needed</code><code>}
private static class Watchdog extends Thread {</code><code>    public void run() {</code><code>        while (true) {</code><code>            AsyncTimeout timedOut = awaitTimeout();</code><code>            if (timedOut == null) continue;</code><code>            timedOut.timedOut();</code><code>        }</code><code>    }</code><code>}

Retrofit Request Construction

Retrofit creates a dynamic proxy for service interfaces, builds a Request, wraps it into an okhttp3.Call, and enqueues it via Dispatcher.promoteAndExecute(). The dispatcher limits concurrent requests by maxRequests (default 64) and per‑host requests by maxRequestsPerHost (default 5).

private boolean promoteAndExecute() {</code><code>    // iterate readyAsyncCalls</code><code>    if (runningAsyncCalls.size() >= maxRequests) break;</code><code>    if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue;</code><code>    // execute asyncCall</code><code>}

When many requests target the same host under poor network conditions, the per‑host limit can cause subsequent calls to wait, effectively extending the observed timeout beyond the configured value.

Root Cause & Solution

Increase maxRequestsPerHost (e.g., from 5 to 8) to allow more concurrent calls to the same host.

Reduce bursty request patterns by merging APIs where possible.

Adjust timeout values to realistic limits rather than maximising them.

These changes resolve the apparent timeout‑not‑triggering issue without altering the underlying OkHttp timeout mechanisms.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaAndroidnetworkTimeoutOkHttpRetrofit
Xueersi Online School Tech Team
Written by

Xueersi Online School Tech Team

The Xueersi Online School Tech Team, dedicated to innovating and promoting internet education technology.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.