Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ConnectionClosedError raised from websockets library #757

Closed
2 tasks done
stefanw opened this issue Aug 17, 2020 · 5 comments
Closed
2 tasks done

ConnectionClosedError raised from websockets library #757

stefanw opened this issue Aug 17, 2020 · 5 comments

Comments

@stefanw
Copy link

stefanw commented Aug 17, 2020

Checklist

  • The bug is reproducible against the latest release and/or master.
  • There are no similar issues or pull requests to fix it yet.

Describe the bug

I'm running a Django project with channels and uvicorn (as a gunicorn worker).

Occasionally, when the server tries to send a message and the client has disconnected improperly, the following exception is raised from the websockets library:

...
  File "channels/consumer.py", line 81, in send
    await self.base_send(message)
  File "channels/sessions.py", line 236, in send
    return await self.real_send(message)
  File "uvicorn/protocols/websockets/websockets_impl.py", line 212, in asgi_send
    await self.send(data)
  File "websockets/protocol.py", line 555, in send
    await self.ensure_open()
  File "websockets/protocol.py", line 812, in ensure_open
    raise self.connection_closed_exc()
ConnectionClosedError

(full traceback under debugging below)

Expected behavior

As a user of channels, I expect not to be required to catch these lower-level exceptions in my message sending code (right? I'm a bit unsure about this). I would expect uvicorn to handle this exception from websockets.

Actual behavior

I have to guard my websocket sending code against exceptions thrown by an implementation detail of the underlying ASGI server. I'm running the daphne ASGI server in development, so this exception handling is unexpected.

Debugging material

Full traceback
CancelledError: null
  File "websockets/protocol.py", line 827, in transfer_data
    message = await self.read_message()
  File "websockets/protocol.py", line 895, in read_message
    frame = await self.read_data_frame(max_size=self.max_size)
  File "websockets/protocol.py", line 971, in read_data_frame
    frame = await self.read_frame(max_size)
  File "websockets/protocol.py", line 1051, in read_frame
    extensions=self.extensions,
  File "websockets/framing.py", line 105, in read
    data = await reader(2)
  File "asyncio/streams.py", line 674, in readexactly
    yield from self._wait_for_data('readexactly')
  File "asyncio/streams.py", line 464, in _wait_for_data
    yield from self._waiter

ConnectionClosedError: code = 1006 (connection closed abnormally [internal]), no reason
  File "uvicorn/protocols/websockets/websockets_impl.py", line 154, in run_asgi
    result = await self.app(self.scope, self.asgi_receive, self.asgi_send)
  File "uvicorn/middleware/proxy_headers.py", line 45, in __call__
    return await self.app(scope, receive, send)
  File "uvicorn/middleware/asgi2.py", line 7, in __call__
    await instance(receive, send)
  File "channels/sessions.py", line 183, in __call__
    return await self.inner(receive, self.send)
  File "channels/middleware.py", line 41, in coroutine_call
    await inner_instance(receive, send)
  File "channels/consumer.py", line 59, in __call__
    [receive, self.channel_receive], self.dispatch
  File "channels/utils.py", line 51, in await_many_dispatch
    await dispatch(result)
  File "channels/consumer.py", line 73, in dispatch
    await handler(message)
  File ".../consumers.py", line 63, in userlist
    'user': event['user']
  File "channels/generic/websocket.py", line 273, in send_json
    await super().send(text_data=await self.encode_json(content), close=close)
  File "channels/generic/websocket.py", line 211, in send
    await super().send({"type": "websocket.send", "text": text_data})
  File "channels/consumer.py", line 81, in send
    await self.base_send(message)
  File "channels/sessions.py", line 236, in send
    return await self.real_send(message)
  File "uvicorn/protocols/websockets/websockets_impl.py", line 212, in asgi_send
    await self.send(data)
  File "websockets/protocol.py", line 555, in send
    await self.ensure_open()
  File "websockets/protocol.py", line 812, in ensure_open
    raise self.connection_closed_exc()

Environment

  • Running uvicorn 0.11.8 with CPython 3.6.6 on Linux
  • Running as a gunicorn worker via uvicorn.workers.UvicornWorker
@euri10
Copy link
Member

euri10 commented Aug 17, 2020

Thanks for the detailed report @stefanw .

What would help would be to know if this happens without gunicorn, just to make sure we throw that out of the equation.

Then if you had a minimal example that would be amazing : I'm not that familiar with channels and I'm like missing ideas on how to "mimic" what you describe as a client disconnecting improperly,

@stefanw
Copy link
Author

stefanw commented Aug 17, 2020

Hey @euri10, I added a passing test in PR #758 that asserts a raised exception under the described condition.

The error only appears with the WebSocketProtocol (based on websockets) and not WSProtocol (based on wsproto), that's why the test only tests that protocol.

In the test I'm calling connection_lost on the protocol to simulate a connection close from the transport without sending a close frame and then try to send some data after. I'm not entirely sure this is the proper way to simulate this, but it does reproduce the exception – and only on the WebSocketProtocol implementation!

@oTree-org
Copy link

What would help would be to know if this happens without gunicorn, just to make sure we throw that out of the equation.

This issue is occurring for me without gunicorn (I am using Django channels also).

@oTree-org
Copy link

FYI If I catch & ignore this exception in the send method of my Django channels consumer (see exception above), I run into this issue: #244

@euri10 euri10 added the bug label May 29, 2021
@Kludex
Copy link
Sponsor Member

Kludex commented Oct 29, 2022

Closing this as stale. Please feel free to reopen with an MRE if this still happens.

@Kludex Kludex closed this as not planned Won't fix, can't repro, duplicate, stale Oct 29, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants