WARNING asyncio.write : socket.send() raised exception.
Long story short
ws.send_json() fails with this warning: WARNING -- asyncio.write : socket.send() raised exception.
ws is from aiohttp.ClientSession().ws_connect()
Expected behaviour
An exception should have be raised along with a traceback message, but nothing happened.
Actual behaviour
It shows the warning and does nothing.
Steps to reproduce
You can see the code here As far as I know, there is no exact way of reproducing it. You just wait a bit for the bug to appear, likely due to some connection errors along the way?
Your environment
aiohttp 3.3.2
Ubuntu 16.04 LTS
Having the same issue in conjunction with this library: https://github.com/graphql-python/graphql-ws
I created the websocket as follows:
ws = web.WebSocketResponse(protocols=('graphql-ws',), heartbeat=5, autoping=True)
I did some debugging. And when closing the connection from the client, I found out that the heartbeat cb _pong_not_received was indeed called. However:
At aiohttp/web_ws.py:
def _pong_not_received(self):
if self._req is not None and self._req.transport is not None:
self._closed = True
self._close_code = 1006
self._exception = asyncio.TimeoutError()
self._req.transport.close()
The if statement did not go through. The underlying transport was already None. The way I see it, the websocket property closed would never be set.
I did a small patch as follows:
@property
def closed(self):
return self._closed or self._req is None or self._req.transport is None
This made everything work on my end. However I don't fully understand all consequences of doing this, and the reasoning behind the current aproach.
@adaptivdesign In my case the connection was never meant to be closed. I have never requested the websocket to be closed so I do not understand why it would want to close itself on its own?
@initzx I assumed the socket.send() exception was because of a broken connection. I was having the same error, once a client disconnected, in which case the websocket did not close on the server end, and resulted in a socket.send() exception.
The logic in the patch helped me, thanks @adaptivdesign.
In my case I was able to easily reproduce this by having a mobile device(running android) connect to the websocket. Background the browser after the connection and wait a short while, this exception message would show in the logs but can not be caught.
Any update or a workaround without patching aiohttp directly?
BTW, this is probably a duplicate of #2309
Asyncio warning: socket.send() exception. I believe it is not aiohttp issue, eventually another frameworks suffer from the same infinite loop exception. after investigation:
- It is the way you feed your data through the socket especially large bits of binary
- server timeout to close the socket is really sensitive and I believe in asyncio is preset to 5 sec. during this five seconds if the socket establish new connection along with big flow of data.
- I tried to lower the timeout or set reusable port and host or catch conn_lost from streamresponse along with exception handling still getting the same result.
finally work around try asyncio.shield() that let the task complete and serve another one 'Gracefully'
async def stream_vid(self, request):
response = web.StreamResponse()
response.content_type = "multipart/x-mixed-replace;boundary=frame"
await response.prepare(request)
try:
while self.sock_opened:
data = self.raw_frame
if not data:
break
await asyncio.shield(response.write(b'--frame\r\n'b'Content-Type: image/jpeg\r\n\r\n' + data + b'\r\n\r\n'))
except BaseException as e:
print("asyncio socket.send() raised exception infinite no more %s" % e)
pass
finally:
print(response.status)
await response.write_eof()
works like a charm further readings https://gitlab.com/pgjones/quart/issues/240
I've stumbled on the same issue.
- open aiohttp server websocket with
autoping=True, heartbeat=5 - open aiohttp client websocket with the same settings
- send some small-ish data through client -> server and server -> client
- starve the client's asyncio event loop for several minutes with blocking load
- send a burst of 100 messages worth 100kb each from client to server
- observe the message 'socket.send() raised exception.' printed on the client's console a hundred-ish times.
Setting the heartbeat on the server side to be safely longer than DOUBLE the time the client is starved (because aiohttp hardcodes self._pong_heartbeat = heartbeat / 2.0) works around the problem.
In my application, I can reproduce the issue 100% of the times. I tried hard to replicate it in a POC, but failed - in the POC, the client is raising sane exceptions instead, either on send() (if the message is enough to saturate the output buffer) or on receive() (for small messages).
@initzx @asvetlov @crusaderky Is there a workaround for this issue ? I have faced with the same issue and due to silent behavior some data was not sent to server from my clients ...
I am interesting in workaround on client-side, because server could be stopped randomly by some reason ...
I wonder how we can use the try...except... to catch this error, or else this will not recover by itself even if the network becomes stable.
socket.send() raised exception.
socket.send() raised exception.
socket.send() raised exception.
socket.send() raised exception.
socket.send() raised exception.
socket.send() raised exception.
socket.send() raised exception.
socket.send() raised exception.
socket.send() raised exception.
socket.send() raised exception.
...
...
app[worker.1]: [13-Jul-24 16:30:11 - WARNING] - asyncio - socket.send() raised exception.
Repo mein ye error ara he koi fixe karwa sakte hai..??
Looks like this is being worked on in cpython: https://github.com/python/cpython/pull/118960 So, hopefully will be resolved in an upcoming release.
Looks like this is being worked on in cpython: python/cpython#118960 So, hopefully will be resolved in an upcoming release.
That fix looks reasonable. We might be able to get rid of cleanup_closed as well
https://github.com/python/cpython/pull/118960 merged \o/
I think this should be fixed in 3.12.7+ and 3.13.1+.
We might be able to get rid of
cleanup_closedas well
@bdraco Do you want to take a look at that?
https://github.com/aio-libs/aiohttp/issues/9590