Search code examples
pythonpython-asyncioaiohttp

Handling premature client disconnection in aiohttp


I am currently testing out aiohttp and I am having a problem with the following code:

async def index(request: web.Request) -> web.StreamResponse:
    response = web.StreamResponse(headers={'content-type': 'text/plain'})
    await response.prepare(request)
    for i in range(1000000):
        try:
            response.write(b'test response')
            await response.drain()
        except concurrent.futures.CancelledError:
            print('Remote connection closed... Cleaning up...')
            # Do cleanup process here?
            raise

    return response

Now I try this out with the following curl request:

curl -v http://127.0.0.1:8080

And then I hit Ctrl-C to cause curl to disconnect and stop downloading the response.

On the console log from the aiohttp web server I get a lot of the following:

2017-11-08 14:42:31,295|WARNING|asyncio|socket.send() raised exception.
2017-11-08 14:42:31,295|WARNING|asyncio|socket.send() raised exception.
2017-11-08 14:42:31,295|WARNING|asyncio|socket.send() raised exception.
2017-11-08 14:42:31,295|WARNING|asyncio|socket.send() raised exception.
2017-11-08 14:42:31,295|WARNING|asyncio|socket.send() raised exception.

Which keeps looping and I cannot kill the server with Ctrl-C. I have to kill it with kill -KILL in order to fully terminate it. It seems that the client socket disconnection is silently handled. I would like to silence the above warnings which are thrown by asyncio.selector_events._SelectorSocketTransport.write(). I could silence that by setting the appropriate logger level, but that's not what I want. Plus there's a lot of cleanup procedures that I would like to do when a client connection terminates. I have looked through the aiohttp code and there doesn't seem to be any handlers or signals that I can hook into to handle it. Ideally I would like to be able to do some cleanup when a client connection is closed.

In Django I am able to do it by creating a custom SelfCleaningStream class with the StreamingHttpResponse class. The custom SelfCleaningStream class handles the cleanup in the close() method which is called by Django when a client connection is closed.


Solution

  • Thanks for report. It is a bug in aiohttp, I've filed an issue