httpx doesn't cancel requests on write timeout #1630
Unanswered
TimOrme
asked this question in
Potential Issue
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
I've raised this issue in the FastAPI repo as well, and not sure what the "correct" behavior should be here.
It appears that if you have a long running httpx client using keep-alive connections, and one of those requests hits a write timeout, httpx doesn't inform the server that the request is over. As such, the server continues to wait for the request data to come in, until the entire connection is closed. This can lead to strange reporting behaviors on the server side, where requests that normally take milliseconds can appear to take several minutes to "complete" before returning an error.
I've created a small test case using FastAPI as the server here:
DockerFile:
FROM tiangolo/uvicorn-gunicorn-fastapi:python3.7
COPY ./app /app
/app/main.py:
from fastapi import FastAPI
from pydantic import BaseModel
import time
class TimingMiddleware:
"""Middleware to track request time."""
app = FastAPI()
app.add_middleware(TimingMiddleware)
class Item(BaseModel):
data: str
@app.post("/endpoint")
def endpoint(item: Item):
return {"Hello": "World"}
test_client.py:
import asyncio
import httpx
import time
async def make_request(client):
# post a big chunk of data
await client.post("http://localhost/endpoint", json={"data": "A" * 10000000})
return "XXX"
async def main():
async with httpx.AsyncClient(timeout=httpx.Timeout(read=5, connect=5, pool=5, write=0.00000000000000000000000000000000000000001)) as client:
tasks = []
for x in range(5):
tasks.append(asyncio.create_task(make_request(client)))
asyncio.run(main())
Start the FastAPI server.
docker build -t timeout .
docker run --rm --name timeout -p 80:80 timeout
Run the test client:
python test_client.py
You'll observe that test_client.py immediately issues timeouts:
%python test_client.py
[WriteTimeout(''), WriteTimeout(''), WriteTimeout(''), WriteTimeout(''), WriteTimeout('')]
But that FastAPI doesn't register any output until 10 seconds later, when the client closes the connections. If you extend the wait time to 3 minutes, the same behavior occurs.
Ideally, it seems like httpx should try to notify the server that it has given up, though I dont know HTTP in detail enough to know if this is even possible.
Also, wasn't sure what the best-practices were around having a single client across a long-running app, such as
celery
orarq
. Initially had set an httpx client up as a single instance for the life of the app, but not sure if that is a problematic approach.Thanks!
Beta Was this translation helpful? Give feedback.
All reactions