title: Python websockets error handling: growing number of threads
body: <p>I have a very simple MWE - two WS connections, one of which will throw an error. Both are executed as tasks and should each recover. Unfortunately, my implementation leads to growing number of threads (one per error). What am I doing wrong here?</p>
  
  <pre><code>import websockets
  import asyncio
  import json
  uri = "wss://echo.websocket.org"
  async def ws(error):
      while True:
          try:
              async with websockets.connect(uri=uri) as websocket:
                  await websocket.send("foo")
                  async for message in websocket:
                      if error:
                          raise ValueError
                      print(message)
          except:
              print('caught a WS exception - going to sleep for 30 seconds')
              websocket.close()
              await asyncio.sleep(30)
  
  
  async def main():
      # try:
      ws_task_error = loop.create_task(ws(error=True))
      ws_task_fine = loop.create_task(ws(False))
      await asyncio.wait([ws_task_error, ws_task_fine], return_when=asyncio.FIRST_EXCEPTION)
  
  if __name__ == '__main__':
      loop = asyncio.get_event_loop()
      loop.run_until_complete(main())
  </code></pre>
  
  <p>It was my understanding that as soon as I leave the context manager of websockets.connect(), the thread in charge should be removed. I'm clearly not implementing it correctly here. Ideas?</p>
  
  <p>----- EDIT ------</p>
  
  <p>I feel the one above is WE, but not really M. This example forces an exception immediately after the connection. In logs, the connection shuts down correctly. Still, I end up creating a new thread upon every connection.</p>
  
  <pre><code>import websockets
  import asyncio
  import logging
  uri = "wss://echo.websocket.org"
  
  logging.basicConfig(format='%(asctime)s %(levelname)s %(name)s: %(message)s')
  logger = logging.getLogger('websockets')
  logger.setLevel(logging.DEBUG)
  
  async def ws():
      while True:
          async with websockets.connect(uri=uri) as websocket:
              try:
                  raise ValueError
              except:
                  print('Exception thrown')
              print('Exiting...')
  
  async def main():
      ws_task_error = loop.create_task(ws())
      await asyncio.wait([ws_task_error], return_when=asyncio.FIRST_EXCEPTION)
  
  if __name__ == '__main__':
      loop = asyncio.get_event_loop()
      loop.run_until_complete(main())
  </code></pre>
  
  <p>OUTPUT:</p>
  
  <pre><code>2020-01-21 10:44:04,710 DEBUG websockets.protocol: client - state = CONNECTING
  2020-01-21 10:44:04,908 DEBUG websockets.protocol: client - event = connection_made(&lt;asyncio.sslproto._SSLProtocolTransport object at 0x00000210389E6828&gt;)
  2020-01-21 10:44:05,001 DEBUG websockets.protocol: client - state = OPEN
  Exception thrown
  Exiting...
  2020-01-21 10:44:05,003 DEBUG websockets.protocol: client - state = CLOSING
  2020-01-21 10:44:05,003 DEBUG websockets.protocol: client &gt; Frame(fin=True, opcode=8, data=b'\x03\xe8', rsv1=False, rsv2=False, rsv3=False)
  2020-01-21 10:44:05,098 DEBUG websockets.protocol: client &lt; Frame(fin=True, opcode=8, data=b'\x03\xe8', rsv1=False, rsv2=False, rsv3=False)
  2020-01-21 10:44:05,099 DEBUG websockets.protocol: client - event = connection_lost(None)
  2020-01-21 10:44:05,100 DEBUG websockets.protocol: client - state = CLOSED
  2020-01-21 10:44:05,100 DEBUG websockets.protocol: client x code = 1000, reason = [no reason]
  2020-01-21 10:44:05,100 DEBUG websockets.protocol: client x closing TCP connection
  2020-01-21 10:44:05,193 DEBUG websockets.protocol: client - state = CONNECTING
  2020-01-21 10:44:05,393 DEBUG websockets.protocol: client - event = connection_made(&lt;asyncio.sslproto._SSLProtocolTransport object at 0x0000021038AB2908&gt;)
  2020-01-21 10:44:05,482 DEBUG websockets.protocol: client - state = OPEN
  Exception thrown
  Exiting...
  2020-01-21 10:44:05,489 DEBUG websockets.protocol: client - state = CLOSING
  2020-01-21 10:44:05,489 DEBUG websockets.protocol: client &gt; Frame(fin=True, opcode=8, data=b'\x03\xe8', rsv1=False, rsv2=False, rsv3=False)
  2020-01-21 10:44:05,580 DEBUG websockets.protocol: client &lt; Frame(fin=True, opcode=8, data=b'\x03\xe8', rsv1=False, rsv2=False, rsv3=False)
  2020-01-21 10:44:05,581 DEBUG websockets.protocol: client - event = connection_lost(None)
  2020-01-21 10:44:05,582 DEBUG websockets.protocol: client - state = CLOSED
  2020-01-21 10:44:05,582 DEBUG websockets.protocol: client x code = 1000, reason = [no reason]
  2020-01-21 10:44:05,583 DEBUG websockets.protocol: client x closing TCP connection
  2020-01-21 10:44:05,670 DEBUG websockets.protocol: client - state = CONNECTING
  2020-01-21 10:44:05,863 DEBUG websockets.protocol: client - event = connection_made(&lt;asyncio.sslproto._SSLProtocolTransport object at 0x0000021038AB2B70&gt;)
  2020-01-21 10:44:05,950 DEBUG websockets.protocol: client - state = OPEN
  Exception thrown
  Exiting...
  2020-01-21 10:44:05,953 DEBUG websockets.protocol: client - state = CLOSING
  2020-01-21 10:44:05,953 DEBUG websockets.protocol: client &gt; Frame(fin=True, opcode=8, data=b'\x03\xe8', rsv1=False, rsv2=False, rsv3=False)
  2020-01-21 10:44:06,036 DEBUG websockets.protocol: client &lt; Frame(fin=True, opcode=8, data=b'\x03\xe8', rsv1=False, rsv2=False, rsv3=False)
  2020-01-21 10:44:06,037 DEBUG websockets.protocol: client - event = connection_lost(None)
  2020-01-21 10:44:06,037 DEBUG websockets.protocol: client - state = CLOSED
  2020-01-21 10:44:06,038 DEBUG websockets.protocol: client x code = 1000, reason = [no reason]
  2020-01-21 10:44:06,039 DEBUG websockets.protocol: client x closing TCP connection
  2020-01-21 10:44:06,124 DEBUG websockets.protocol: client - state = CONNECTING
  2020-01-21 10:44:06,308 DEBUG websockets.protocol: client - event = connection_made(&lt;asyncio.sslproto._SSLProtocolTransport object at 0x0000021038AC6C50&gt;)
  2020-01-21 10:44:06,400 DEBUG websockets.protocol: client - state = OPEN
  Exception thrown
  Exiting...
  2020-01-21 10:44:06,402 DEBUG websockets.protocol: client - state = CLOSING
  2020-01-21 10:44:06,402 DEBUG websockets.protocol: client &gt; Frame(fin=True, opcode=8, data=b'\x03\xe8', rsv1=False, rsv2=False, rsv3=False)
  2020-01-21 10:44:06,495 DEBUG websockets.protocol: client &lt; Frame(fin=True, opcode=8, data=b'\x03\xe8', rsv1=False, rsv2=False, rsv3=False)
  2020-01-21 10:44:06,496 DEBUG websockets.protocol: client - event = connection_lost(None)
  2020-01-21 10:44:06,496 DEBUG websockets.protocol: client - state = CLOSED
  2020-01-21 10:44:06,496 DEBUG websockets.protocol: client x code = 1000, reason = [no reason]
  2020-01-21 10:44:06,497 DEBUG websockets.protocol: client x closing TCP connection
  2020-01-21 10:44:06,600 DEBUG websockets.protocol: client - state = CONNECTING
  2020-01-21 10:44:06,827 DEBUG websockets.protocol: client - event = connection_made(&lt;asyncio.sslproto._SSLProtocolTransport object at 0x0000021038AC6B70&gt;)
  2020-01-21 10:44:06,934 DEBUG websockets.protocol: client - state = OPEN
  Exception thrown
  Exiting...
  2020-01-21 10:44:06,936 DEBUG websockets.protocol: client - state = CLOSING
  2020-01-21 10:44:06,936 DEBUG websockets.protocol: client &gt; Frame(fin=True, opcode=8, data=b'\x03\xe8', rsv1=False, rsv2=False, rsv3=False)
  2020-01-21 10:44:07,042 DEBUG websockets.protocol: client &lt; Frame(fin=True, opcode=8, data=b'\x03\xe8', rsv1=False, rsv2=False, rsv3=False)
  2020-01-21 10:44:07,043 DEBUG websockets.protocol: client - event = connection_lost(None)
  2020-01-21 10:44:07,044 DEBUG websockets.protocol: client - state = CLOSED
  2020-01-21 10:44:07,044 DEBUG websockets.protocol: client x code = 1000, reason = [no reason]
  2020-01-21 10:44:07,045 DEBUG websockets.protocol: client x closing TCP connection
  </code></pre>