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()을 await하여 수행합니다. 읽지 않은 응답을 닫으면 용량은 확보되지만, 기반 연결을 재사용하지 못하고 버려야 할 수 있습니다.
예외 이름 읽기
ConnectTimeout은 연결 설정, ReadTimeout은 응답 데이터 대기, PoolTimeout은 연결 슬롯 확보에 관한 예외입니다. 로그에 «프록시 시간 초과»만 남기면 해결책을 고르는 데 필요한 구분이 사라집니다.
엔드포인트 IP를 바꾸기 전에 열린 응답, 동시 작업, 연결 제한을 확인하세요. 정상적인 동시 부하에는 더 큰 풀이 적절할 수 있지만 닫지 않는 응답을 고치지는 못합니다. 애플리케이션이 차지할 수 있는 용량만 늘어납니다.
전체 작업에서 클라이언트를 재사용할 수 있게 유지하세요. 각 요청이 되는 것처럼 보이게 하려고 클라이언트를 다시 만들면 수명 관리 문제를 감추고 연결 재사용을 잃을 수 있습니다.