0

In the minimal snippet bellow with both client producer/consumers and server, I force an error on the client's send method:

import asyncio
import websockets


async def producer(websocket):
    for i in range(11):
        await websocket.send(i)  # Invalid type, fails silently
        # await websocket.send(str(i))  # Works


async def consumer(websocket):
    async for msg in websocket:
        i = int(msg)
        print(i)
        if i == 10:
            return


async def echo(websocket, path):
    try:
        async for msg in websocket:
            await websocket.send(msg)
    except websockets.exceptions.ConnectionClosedOK:
        print("Client disconnect.")


async def client():
    async with websockets.connect("ws://localhost:8765") as websocket:
        consumer_task = consumer(websocket)
        producer_task = producer(websocket)
        await asyncio.wait([consumer_task, producer_task])


loop = asyncio.get_event_loop()
loop.run_until_complete(websockets.serve(echo, "localhost", 8765))
loop.run_until_complete(client())

In the invalid type case, the code hangs indefinitely, seemingly as it had "failed silently". Shouldn't the send method raise an exception due to the invalid int type (since it only accepts bytes or str)?

amiasato
  • 914
  • 6
  • 14
  • 1
    I'm not too familiar with `async` and `await` in Python, but I'm guessing `await asyncio.wait([consumer_task, producer_task])` will first wait for `consumer_task` to finish, before propagating any exception raised _asynchronously_ from `producer_task`. – Thomas Feb 11 '21 at 13:22
  • 1
    If I'm looking at the right code [here](https://github.com/aaugustin/websockets/blob/aa93c4ceca90a1798f86b2fc2b110a42f308d721/src/websockets/legacy/protocol.py#L672) then an exception _is_ raised when passing `data` of the wrong type. – Thomas Feb 11 '21 at 13:27
  • Indeed, I put a `return_when=asyncio.FIRST_EXCEPTION` as argument for the `asyncio.wait`, and at least now the code does not hang indefinitely. I'm trying to figure out now how to re-raise the exception from the future (though I guess it should be re-raised by default). – amiasato Feb 11 '21 at 13:30

1 Answers1

1

The problem was actually lying in the asyncio.wait method, as hinted by Thomas' comments (thanks). Switching asyncio.wait for the higher-level asyncio.gather solved it.

amiasato
  • 914
  • 6
  • 14