Issue
I have an app that gets messages from a Python server through a websocket connection. If the client gets disconnected in between, the server won't be able to send messages. I want to leverage this and raise an exception when this happens in order to properly clean up without lots of errors.
async def status(websocket, message):
try:
print("\nDEBUG: "+message)
await asyncio.wait([websocket.send(message)])
except:
raise Abort()
This function throws an error when the client gets disconnected.
DEBUG: Waiting for sale to start
Task exception was never retrieved
future: <Task finished name='Task-79' coro=<WebSocketCommonProtocol.send() done, defined at C:\Users\321vi\AppData\Local\Programs\Python\Python38\lib\site-packages\websockets\protocol.py:521> exception=ConnectionClosedError('code = 1006 (connection closed abnormally [internal]), no reason')>
Traceback (most recent call last):
File "C:\Users\321vi\AppData\Local\Programs\Python\Python38\lib\site-packages\websockets\protocol.py", line 827, in transfer_data
message = await self.read_message()
File "C:\Users\321vi\AppData\Local\Programs\Python\Python38\lib\site-packages\websockets\protocol.py", line 895, in read_message
frame = await self.read_data_frame(max_size=self.max_size)
File "C:\Users\321vi\AppData\Local\Programs\Python\Python38\lib\site-packages\websockets\protocol.py", line 971, in read_data_frame
frame = await self.read_frame(max_size)
File "C:\Users\321vi\AppData\Local\Programs\Python\Python38\lib\site-packages\websockets\protocol.py", line 1047, in read_frame
frame = await Frame.read(
File "C:\Users\321vi\AppData\Local\Programs\Python\Python38\lib\site-packages\websockets\framing.py", line 105, in read
data = await reader(2)
File "C:\Users\321vi\AppData\Local\Programs\Python\Python38\lib\asyncio\streams.py", line 721, in readexactly
raise exceptions.IncompleteReadError(incomplete, n)
asyncio.exceptions.IncompleteReadError: 0 bytes read on a total of 2 expected bytes
Now, I understand that this is due to improper handling of exceptions with asyncio
as mentioned in the docs, but I'm unable to write a proper handler
to handle the exceptions. I did try to copy this answer and make it work. But then it doesn't send any message at all. And there are surprisingly no error messages at all either. Here's my code after copy pasting
async def status(websocket, message):
print("\nDEBUG: "+message)
done, pending = await asyncio.wait([websocket.send(message)])
assert not pending
future, = done
if future.exception() is websockets.ConnectionClosedError:
raise Abort()
I also tried stripping off asyncio.wait()
and using simple websocket.send()
but that doesn't work well with this app. I'm not experienced with Python's Future
so any help would be greatly appreciated. Technically, I might be able to use heartbeats
to check if the connection is alive every time but that can be more network consuming so I prefer not to.
Solution
If you are awaiting only one coroutine, do it directly and exceptions will be naturally propagated:
try
print("\nDEBUG: "+message)
await websocket.send(message)
except Exception:
raise Abort()
There is no reason to use asyncio.wait
which is designed to wait for several tasks. Using it for one coroutine creates lots of overhead: a new task is created, scheduled, run and finally returned in an one-element set and its result must be checked in a separate step. That is basically what the last code snippet does.
Simple websocket.send(message)
(when defined with async def
) without the await
practically does nothing. Technically it creates a couroutine object from a coroutine function, but that couroutine is not executed.
Answered By - VPfB
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.