aio-libs / aio-libs/aiohttp

Websocket reading message loop raises low-level CanceledError when connection is closed unexpectedly

Đang mở
#2,061 4 bình luận 2 reaction 0 người được giao Xem trên GitHub
enhancement
Ngôn ngữ chính
Python
Star
16.5k
Fork
2.4k
Merge trung bình
17 giờ 22 phút
Pull request đã merge (30 ngày)
212

Mô tả

## Actual behaviour

Reading message loop `async for msg in ws:` raises low-level `concurrent.futures._base.CancelledError` when connection is closed unexpectedly.

## Expected behaviour

Expected to get message with type `aiohtto.http_websocket.WSMsgType.ERROR`, or silently stop the loop, or at least `aiohtto.http_websocket.WebSocketError`.

## Steps to reproduce

Run the following two scripts `server.py` and `client.py`, then stop `client.py` by `Ctrl+C`.

### server.py
```python
import logging

from aiohttp import web

logger = logging.getLogger(__name__)

async def index(request):
ws = web.WebSocketResponse()
request.app['websockets'].add(ws)

try:
await ws.prepare(request)
logger.debug('Connected')
async for msg in ws:
logger.info('Received: %r', msg.data)
except Exception:
logger.exception('Error')
logger.debug('Disconnected')

request.app['websockets'].discard(ws)
return ws

async def on_shutdown(app):
for ws in app['websockets']:
await ws.close()
app['websockets'].clear()

def main():
logging.basicConfig(level=logging.DEBUG)

app = web.Application()
app['websockets'] = set()
app.router.add_get('/', index)
app.on_shutdown.append(on_shutdown)

web.run_app(app, host='127.0.0.1', port=9000)

if __name__ == '__main__':
main()
```
### client.py
```python
import asyncio

import aiohttp

async def communicate(loop):
async with aiohttp.ClientSession(loop=loop) as session:
async with session.ws_connect('http://127.0.0.1:9000') as ws:
while True:
await ws.send_str('Hello')
await asyncio.sleep(1, loop=loop)

def main():
loop = asyncio.get_event_loop()
loop.run_until_complete(communicate(loop))

if __name__ == '__main__':
main()
```
### Log output of `server.py`
```
$ python server.py
DEBUG:asyncio:Using selector: EpollSelector
======== Running on http://127.0.0.1:9000 ========
(Press CTRL+C to quit)
DEBUG:__main__:Connected
INFO:__main__:Received: 'Hello'
INFO:__main__:Received: 'Hello'
INFO:__main__:Received: 'Hello'
INFO:__main__:Received: 'Hello'
INFO:__main__:Received: 'Hello'
INFO:__main__:Received: 'Hello'
INFO:__main__:Received: 'Hello'
INFO:__main__:Received: 'Hello'
INFO:__main__:Received: 'Hello'
ERROR:__main__:Error
Traceback (most recent call last):
File "server.py", line 16, in index
async for msg in ws:
File "/home/vagrant/project/workspace/pyenv_dev/lib64/python3.5/site-packages/aiohttp/web_ws.py", line 343, in __anext__
msg = yield from self.receive()
File "/home/vagrant/project/workspace/pyenv_dev/lib64/python3.5/site-packages/aiohttp/web_ws.py", line 273, in receive
msg = yield from self._reader.read()
File "/home/vagrant/project/workspace/pyenv_dev/lib64/python3.5/site-packages/aiohttp/streams.py", line 627, in read
return (yield from super().read())
File "/home/vagrant/project/workspace/pyenv_dev/lib64/python3.5/site-packages/aiohttp/streams.py", line 509, in read
yield from self._waiter
File "/usr/lib64/python3.5/asyncio/futures.py", line 380, in __iter__
yield self # This tells Task to wait for completion.
File "/usr/lib64/python3.5/asyncio/tasks.py", line 304, in _wakeup
future.result()
File "/usr/lib64/python3.5/asyncio/futures.py", line 285, in result
raise CancelledError
concurrent.futures._base.CancelledError
DEBUG:__main__:Disconnected
INFO:aiohttp.access:- - - [06/Jul/2017:11:41:25 +0000] "GET / HTTP/1.1" 101 0 "-" "Python/3.5 aiohttp/2.2.3"
```

## Your environment

OS: CentOS Linux 7
Linux kernel: 3.10.0-514.16.1.el7.x86_64
Python: 3.5.3
aiohttp: 2.2.3

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.