uvicorn icon indicating copy to clipboard operation
uvicorn copied to clipboard

After making a few POST requests with large body and small keep-alive, one of the requests ends with the connection aborted.

Open wb7777 opened this issue 2 years ago • 3 comments

After making a few POST requests with large body and small keep-alive, one of the requests ends with the connection aborted.
The server said thats all right, but connection is aborted

It seems similar to #1345, but different.

uvicorn: 0.23.2

How to reproduce:

Server side:

# test.py
from starlette.requests import Request
from starlette.responses import Response
from starlette.applications import Starlette
from starlette.routing import Route


async def test(request: Request):
    await request.body()
    return Response()


routes = [
    Route("/test", endpoint=test, methods=['post'])
]

app = Starlette(debug=True, routes=routes)

Uvicorn start:

uvicorn --timeout-keep-alive 1 test:app

Client side:

import asyncio
import aiohttp


should_stop = False


async def worker(session):
    global should_stop

    try:
        async with session.post('http://localhost:8000/test', data='x' * 100_000_000) as response:
            print(f"Status:", response.status)
    except:
        should_stop = True
        raise


async def main():
    async with aiohttp.ClientSession() as session:
        tasks = []
        while not should_stop:
            tasks.append(asyncio.create_task(worker(session)))

            await asyncio.sleep(0)

        done, _ = await asyncio.wait(tasks)

        [x.result() for x in done if x.exception()]


asyncio.run(main())

After several iterations, one of the exceptions occurs:

  File "/Users/wb77/.pyenv/versions/3.11.1/envs/integration.intas.sync/lib/python3.11/site-packages/aiohttp/streams.py", line 616, in read
    await self._waiter
aiohttp.client_exceptions.ClientOSError: [Errno 32] Broken pipe
  File "/Users/wb77/.pyenv/versions/3.11.1/envs/integration.intas.sync/lib/python3.11/site-packages/aiohttp/http_writer.py", line 75, in _write
    raise ConnectionResetError("Cannot write to closing transport")
ConnectionResetError: Cannot write to closing transport

and some another exceptions.

If we increase keep-alive timeout, the frequency of error is reduced.

Originally posted by @wb7777 in https://github.com/encode/uvicorn/discussions/2021

wb7777 avatar Sep 11 '23 07:09 wb7777

May be related to https://github.com/django/asgiref/issues/66. I'm not sure.

I'll investigate.

Kludex avatar Sep 11 '23 08:09 Kludex

when i run this:

uvicorn  --timeout-keep-alive 1 test:app

and run client script, the first output on client side is:

$ python client.py
killed

server side:

...
starlette.requests.ClientDisconnect

the server still running, so i ran client script again and after some iterations: (client side output)

...
aiohttp.client_exceptions.ClientOsError [Errno 32] Broken Pipe

ghost avatar Sep 15 '23 12:09 ghost