Proxy request timeout budget workflow

A single “30-second timeout” hides several different waits: DNS, proxy connection, TLS negotiation, proxy authentication, time to first byte, response reading, and retry delay. When these stages share one vague limit, failures become hard to diagnose and retries can multiply traffic long after the user-facing deadline has passed.

A reliable proxy workflow starts with one end-to-end deadline, then divides it into stage budgets.

Start with the business deadline

Define the maximum useful time for the whole operation. A checkout verification, search result collection, and overnight dataset job have different deadlines. The total budget must include every attempt, backoff delay, queue wait, and response-processing step.

For example, if an operation is no longer useful after 20 seconds, three attempts with 10-second timeouts cannot fit. Set an absolute deadline and pass the remaining time to each stage.

Separate the stages

DNS and endpoint selection

Measure how long it takes to resolve the proxy hostname and select an address family. Local and remote DNS modes can behave differently. Cache carefully and record whether IPv4 or IPv6 was chosen.

Proxy connection

The connect timeout should cover TCP establishment to the proxy, not the entire request. A short connect budget catches unreachable endpoints quickly, but it must account for realistic cross-region latency.

TLS and authentication

HTTPS proxies and HTTPS destinations can involve separate secure handshakes. Proxy authentication can also add a round trip. Record these stages independently when the client exposes timing data.

Time to first byte

After the request is sent, the first-byte budget measures proxy processing plus destination response time. A healthy connection with a slow first byte is different from a failed connection.

Response reading

Large downloads need a read or idle timeout, not merely a fixed total timeout. An idle timeout should reset when useful data arrives, while the end-to-end deadline still prevents an operation from running forever.

Build a budget from percentiles

Use real measurements, not averages. Track p50, p95, and p99 for connect, handshake, first byte, and total duration by region and task type. A timeout set near the average will reject many normal requests. A timeout far above p99 will delay failure recovery.

Start slightly above the expected high percentile, then monitor timeout rate, success rate, and cost per usable result. Revisit budgets after changing region, concurrency, destination mix, or proxy type.

Retry only eligible failures

Retries are appropriate for transient connect failures, selected timeouts, and some server errors. They are usually wrong for invalid credentials, policy rejections, malformed requests, or deterministic destination blocks.

Use exponential backoff with jitter and keep it inside the remaining deadline. Before each retry, ask:

  • Is the error transient?
  • Is the operation safe to repeat?
  • Is there enough deadline remaining for another useful attempt?
  • Would switching endpoint or session change the failure mode?

Prevent retry storms

When many workers time out together, immediate retries can overload the proxy and destination. Add jitter, global concurrency limits, per-destination rate limits, and a circuit breaker. Stop sending new attempts when the recent failure rate crosses a defined threshold.

Avoid multiplying retries across layers. If the HTTP library retries three times and the job queue retries the task three times, one logical request can become nine network attempts.

Python example with a shared deadline

import time
import random
import requests

deadline = time.monotonic() + 20
attempt = 0

while attempt < 3:
    remaining = deadline - time.monotonic()
    if remaining <= 1:
        raise TimeoutError("operation deadline exhausted")

    connect_timeout = min(4, remaining / 3)
    read_timeout = max(1, remaining - connect_timeout)

    try:
        response = requests.get(
            "https://en.98ip.com/",
            proxies={"http": PROXY_URL, "https": PROXY_URL},
            timeout=(connect_timeout, read_timeout),
        )
        response.raise_for_status()
        break
    except (requests.ConnectTimeout, requests.ReadTimeout):
        attempt += 1
        delay = min(2 ** attempt + random.random(), deadline - time.monotonic())
        if delay <= 0:
            raise
        time.sleep(delay)

Keep PROXY_URL in a protected secret source and never print it. Production code should also classify HTTP errors, cap response size, and emit redacted stage metrics.

What to log

Log timestamps, task type, region, proxy endpoint identifier, attempt number, connection duration, first-byte time, total time, status class, timeout stage, and final outcome. Do not log credentials, authorization headers, session tokens, cookies, or complete credential-bearing URLs.

Use one correlation identifier for the logical operation and separate identifiers for attempts. This reveals retry amplification without exposing private data.

Production checklist

  • One absolute deadline covers the whole operation.
  • Connect, handshake, first-byte, and read stages are distinguishable.
  • Budgets are based on regional percentile data.
  • Retries are limited to transient and repeatable failures.
  • Backoff and jitter fit inside the remaining deadline.
  • Library and queue retries are not multiplied.
  • Concurrency and circuit breakers prevent storms.
  • Logs are stage-aware and credential-free.
  • IPv4, IPv6, local DNS, and remote DNS paths are tested.
  • Usage follows applicable law, destination terms, and data rules.

For controlled proxy testing across regions and workloads, review the configuration information on 98IP. Measure each stage before increasing timeout values or retry counts.

Research basis: Requests timeout documentation; curl connection and maximum-time documentation; reliability engineering practices for deadlines, backoff, and jitter. Source names are listed without external links.