HTTPX PoolTimeout — не тайм-аут соединения с прокси
Распознайте ожидание пула соединений HTTPX и освобождайте потоковые ответы, прежде чем менять прокси, который мог не получить новый запрос.
PoolTimeout означает, что HTTPX не получил соединение из пула за настроенное время ожидания. Это не доказывает тайм-аут нового TCP-соединения с прокси. Второй запрос может всё ещё ждать внутри вашего процесса.
Это легко воспроизвести, если клиент допускает одно соединение, а первый потоковый ответ остаётся открытым. Запуск другого запроса не освобождает соединение сам по себе.
Явно обозначьте ответственность за потоковый ответ
import httpx
limits = httpx.Limits(
max_connections=1,
max_keepalive_connections=1,
)
timeout = httpx.Timeout(
connect=5, read=10, write=10, pool=1
)
with httpx.Client(
proxy="http://203.0.113.10:8080",
trust_env=False,
limits=limits,
timeout=timeout,
) as client:
with client.stream("GET", "https://example.com/") as response:
print(response.status_code)
for chunk in response.iter_bytes():
print(len(chunk))
next_response = client.get("https://example.com/")
print(next_response.status_code)
Перед запуском замените документационный адрес прокси. Следующий запрос начинается после выхода из контекста потока. Выход закрывает ответ даже при прерывании цикла или исключении.
При ручном потоковом режиме, например client.send(request, stream=True), за окончательное закрытие отвечает ваш код. В AsyncClient соответствующую ручную очистку ожидают через response.aclose(). Закрытие непрочитанного ответа освобождает ёмкость, но может потребовать отбросить нижележащее соединение вместо повторного использования.
Читайте имя исключения
ConnectTimeout относится к установлению соединения. ReadTimeout — к ожиданию данных ответа. PoolTimeout — к получению места под соединение. Запись лишь «тайм-аут прокси» теряет различие, необходимое для выбора исправления.
Прежде чем менять IP конечных точек, проверьте открытые ответы, параллельные задачи и ограничения соединений. Больший пул может подходить оправданной параллельной нагрузке, но не исправит ответы, которые никогда не закрываются. Он лишь даёт приложению больше места для занятия.
Сохраняйте клиент для повторного использования на протяжении нагрузки. Пересоздание клиента ради видимой работоспособности каждого запроса может скрыть проблему жизненного цикла и лишить повторного использования соединений.