Skip to content

Chapter 7 · Timeouts and Retries ​

Chapter goals: master timeout configuration and retry strategies in requests and httpx so requests never hang forever or retry endlessly.

7.1 Why You Need Timeouts ​

Requests without timeouts are one of the most common sources of production incidents. Picture this: your service calls a third-party payment API and their server goes down without closing the TCP connection — your request hangs indefinitely until every worker thread is exhausted, and your whole service cascades down.

python
import requests

# Dangerous: no timeout, could hang forever
resp = requests.get('https://slow-api.example.com/data')

# Correct: set a timeout
resp = requests.get('https://slow-api.example.com/data', timeout=5)

Timeouts have two dimensions:

  • Connect timeout: the longest wait for the TCP handshake to complete;
  • Read timeout: the longest wait for the server to return data.

7.2 Timeout Configuration in requests ​

The timeout argument in requests accepts two forms:

python
import requests

# Option 1: a single value (connect + read share it)
resp = requests.get('https://httpbin.org/delay/1', timeout=5)

# Option 2: a tuple (connect_timeout, read_timeout)
resp = requests.get('https://httpbin.org/get', timeout=(3, 10))
# connect within 3 seconds; read the response within 10

When a timeout fires, requests raises requests.exceptions.Timeout:

python
try:
    resp = requests.get('https://httpbin.org/delay/10', timeout=2)
except requests.exceptions.Timeout:
    print('Request timed out')

7.3 Retries with HTTPAdapter ​

requests implements automatic retries via urllib3's Retry mechanism. First register an HTTPAdapter:

python
import requests
from urllib3.util.retry import Retry
from requests.adapters import HTTPAdapter

# Build a retry strategy
retry_strategy = Retry(
    total=3,                          # max retries
    backoff_factor=1,                 # intervals: 0s, 1s, 2s...
    status_forcelist=[429, 500, 502, 503, 504],  # only retry these statuses
    allowed_methods=["GET", "POST"]   # only retry these methods
)

# Mount onto a session
session = requests.Session()
session.mount('https://', HTTPAdapter(max_retries=retry_strategy))
session.mount('http://', HTTPAdapter(max_retries=retry_strategy))

# Requests through the session now retry automatically
resp = session.get('https://httpbin.org/status/500')

backoff_factor controls retry waits: the Nth retry waits backoff_factor × (2^(N-1)) seconds. With backoff_factor=1, intervals are 0, 1, 2, 4 seconds.

7.4 Timeout Configuration in httpx ​

httpx has a finer-grained timeout system with four timeout types:

python
import httpx

# Option 1: single timeout
with httpx.Client(timeout=10.0) as client:
    resp = client.get('https://httpbin.org/get')

# Option 2: fine-grained configuration
timeout = httpx.Timeout(
    connect=3.0,    # connect within 3 seconds
    read=10.0,      # read within 10 seconds
    write=30.0,     # write within 30 seconds
    pool=5.0        # wait at most 5 seconds for a pooled connection
)

with httpx.Client(timeout=timeout) as client:
    resp = client.get('https://httpbin.org/get')

httpx raises dedicated exceptions on timeout: ConnectTimeout, ReadTimeout, WriteTimeout, PoolTimeout.

7.5 Combining Retries and Timeouts ​

Production environments usually need both timeouts and retries together:

python
import httpx
from httpx import Timeout

# Fine-grained timeouts + retries
timeout = Timeout(connect=5.0, read=30.0, write=10.0, pool=5.0)
limits = httpx.Limits(max_connections=100, max_keepalive_connections=20)

with httpx.Client(timeout=timeout, limits=limits) as client:
    try:
        resp = client.get('https://api.example.com/data')
        resp.raise_for_status()
    except httpx.ConnectTimeout:
        print('Connect timeout')
    except httpx.ReadTimeout:
        print('Read timeout')
    except httpx.HTTPStatusError as e:
        print(f'HTTP error: {e.response.status_code}')

7.6 Chapter Summary ​

  • Timeouts are essential production protection against hanging requests;
  • requests uses a (connect, read) tuple for dual timeouts;
  • httpx provides a Timeout object supporting connect/read/write/pool;
  • Smart retries come from HTTPAdapter + Retry; combine with backoff_factor to avoid avalanches.

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. Which formats does the requests timeout argument accept?

2. With urllib3 Retry backoff_factor=1, how long is the wait before the third retry?

3. Which of these is NOT an httpx timeout type?

4. Which approach best fits production HTTP calls?

🛠️ Hands-On Exercises ​

  1. Test timeouts: call https://httpbin.org/delay/5 with a 2-second timeout; catch and print the exception.
  2. Build a session with retries: retry https://httpbin.org/status/500 up to 3 times with 1-second intervals and log each retry.
  3. Configure fine-grained timeouts in httpx and compare the four timeout exception types.

After finishing the exercises, move on to the next chapter.