WebSocket-for-Python icon indicating copy to clipboard operation
WebSocket-for-Python copied to clipboard

Avoid ResourceWarning if shutdown failed for some reason

Open jolaf opened this issue 4 years ago • 3 comments

The following warning appears transiently from time to time while working with websockets:

/usr/lib/python3/dist-packages/ws4py/websocket.py:230: ResourceWarning: unclosed <ssl.SSLSocket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('10.25.11.39', 40618)>
  self.sock = None
ResourceWarning: Enable tracemalloc to get the object allocation traceback

Investigation shows that this warning appears if self.sock.shutdown(socket.SHUT_RDWR) (line 225) throws exception and thus self.sock.close() (line 226) is not called and execution proceeds straight to self.sock = None (line 230), and that produces the ResourceWarning mentioned above.

The exception itself is hidden by pass statement (line 228), but additional investigation showed the following example of that exception:

File "/usr/lib/python3/dist-packages/ws4py/websocket.py", line 225, in close_connection
    self.sock.shutdown(socket.SHUT_RDWR)
  File "/usr/lib/python3.8/ssl.py", line 1280, in shutdown
    super().shutdown(how)
OSError: [Errno 107] Transport endpoint is not connected

The reliable reproduction of this situation is problematic, but I've created the following test that reproduces the problem reliably and should pass if the problem is fixed:

from ws4py.client.threadedclient import WebSocketClient
  
def received_message(self, m):
    self.close()

def opened(self):
    self.send('blah\n' * 10000)

def shutdown(self):
    raise Exception('shutdown')

def close_connection(self):
    self.sock.shutdown = shutdown
    original_close_connection(self)

WebSocketClient.received_message = received_message
WebSocketClient.opened = opened

original_close_connection = WebSocketClient.close_connection

WebSocketClient.close_connection = close_connection

ws = WebSocketClient('wss://websocketstest.com/service')
ws.connect()
ws.run_forever()

Here's the output:

$ python3 -W all test.py 
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/ws4py/websocket.py", line 225, in close_connection
    self.sock.shutdown(socket.SHUT_RDWR)
  File "test.py", line 10, in shutdown
    raise Exception('shutdown')
Exception: shutdown

/usr/lib/python3/dist-packages/ws4py/websocket.py:231: ResourceWarning: unclosed <ssl.SSLSocket fd=3, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('192.168.1.4', 50110), raddr=('88.198.55.153', 443)>
  self.sock = None
ResourceWarning: Enable tracemalloc to get the object allocation traceback

$ python3
Python 3.8.10 (default, Sep 28 2021, 16:10:42) 
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import ws4py
>>> ws4py.__version__
'0.5.1'

$ uname -a
Linux i-buildcore-01-11 5.4.0-89-generic #100-Ubuntu SMP Fri Sep 24 14:50:10 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

$ cat /etc/issue
Ubuntu 20.04.3 LTS \n \l

jolaf avatar Oct 09 '21 21:10 jolaf

I've provided a test to reproduce the problem.

jolaf avatar Nov 01 '21 21:11 jolaf