简体   繁体   中英

Python websockets get stuck

I have a python server that is available through a websocket endpoint. During serving a connection, it also communicates with some backend services. This communication is asynchronous and may trigger the send() method of the websocket.

When a single client is served, it seems to work ok. However, when multiple clients are served in parallel, some of the routines that handle the connections get stuck occasionally. More precisely, it seem to block in the recv() method.

The actual code is somehow complex and the issue is slightly more complicated than I have described, nevertheless, I provide a minimal skeleton of code that sketch the way in which I use he websockets:

class MinimalConversation(object):

    def __init__(self, ws, worker_sck, messages, should_continue_conversation, should_continue_listen):
        self.ws = ws
        self.messages = messages
        self.worker_sck = worker_sck
        self.should_continue_conversation = should_continue_conversation
        self.should_continue_listen = should_continue_listen

async def run_conversation(self):
        serving_future = asyncio.ensure_future(self.serve_connection())
        listening_future = asyncio.ensure_future(self.handle_worker())
        await asyncio.wait([serving_future, listening_future], return_when=asyncio.ALL_COMPLETED)

async def serve_connection(self):
        while self.should_continue_conversation():
            await self.ws.recv()
            logger.debug("Message received")
            self.sleep_randomly(10, 5)
            await self.worker_sck.send(b"Dummy")

async def handle_worker(self):
        while self.should_continue_listen():
            self.sleep_randomly(50, 40)
            await self.worker_sck.recv()
            await self.ws.send(self.messages.pop())

def sleep_randomly(self, mean, dev):
        delta = random.randint(1, dev) / 1000
        if random.random() < .5:
            delta *= -1
        time.sleep(mean / 1000 + delta)

Obviously, in the real code I do not sleep for random intervals and don't use given list of messages but this sketches the way I handle the websockets. In the real setting, some errors may occur that are sent over the websocket too, so parallel sends() may occur in theory but I have never encountered such a situation.

The code is run from a handler function which is passed as a parameter to websockets.serve(), initialize the MinimalConversation object and calls the run_conversation() method.

My questions are:

  • Is there something fundamentally wrong with such usage of the websockets?
  • Are concurrent calls of the send() methods dangerous?
  • Can you suggest some good practices regarding usage of websockets and asyncio?

Thak you.

recv function yields back only when a message is received, and it seems that there are 2 connections awaiting messages from each other, so there might be a situation similar to "deadlock" when they are waiting for each other's messages and can't send anything. Maybe you should try to rethink the overall algorithm to be safer from this.

And, of course, try adding more debug output and see what really happens.

are concurrent calls of the send() methods dangerous?

If by concurrent you mean in the same thread but in independently scheduled coroutines then parallel send is just fine. But be careful with "parallel" recv on the same connection, because order of coroutine scheduling might be far from obvious and it's what decides which call to recv will get a message first.

Can you suggest some good practices regarding usage of websockets and asyncio?

In my experience, the easiest way is to create a dedicated task for incoming connections which will repeatedly call recv on the connection, until connection is closed. You can store the connection somewhere and delete it in finally block, then it can be used from other coroutines to send something.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM