memnonila
memnonila

Reputation: 359

Django Channels websocket communication not truly asynchronous?

I wrote django channels code to send api data from two different sources asynchronously through websockets. The different sources takes few seconds to 1 minute to compute and send back the data. I managed to call them asynchronously using asyncio event loop. But the issue is that they are not sending the response back asynchronously. The code just waits for the all the data to arrive and sends everything at the same time.

Channels Code:

class SearchHotelConsumer(AsyncWebsocketConsumer):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.source1 = Source1()
        self.source2 = Source2()

    async def connect(self):
        await self.accept()

    def disconnect(self, close_code):
        pass

    async def _source1_handler(self, request, queue):
        source1_response = await self.source1.async_post(request)

        await queue.put(source1_response.data)

    async def _source2_handler(self, request, queue):
        source2_response = await self.source2.async_post(request)

        await queue.put(source2_response.data)

    async def _send_msg(self, queue):
        while True:
            message = await queue.get()
            if message is None:
                break
            print('got the message')
            await self.send(text_data=json.dumps({
                'message': message
            }, cls=DjangoJSONEncoder))

            queue.task_done()

    def receive(self, text_data):
        text_data_json = json.loads(text_data)
        message = text_data_json['message']

        request = HttpRequest()
        request.method = 'POST'
        request.session = self.scope["session"]
        request = Request(request)
        for key, val in message.items():
            request.data[key] = val

        queue = asyncio.Queue()
        sender = asyncio.ensure_future(self._send_msg(queue))

        await self._source1_handler(request, queue)
        await self._source2_handler(request, queue)

        await queue.join()

        sender.cancel()

How can I make the message sending part truly asynchronous?

Upvotes: 2

Views: 806

Answers (1)

MarkReedZ
MarkReedZ

Reputation: 1437

Your async_post code which is not shown is probably synchronous.

If you want async requests see this answer:

https://stackoverflow.com/a/22414756/10840818

To use requests (or any other blocking libraries) with asyncio, you can use BaseEventLoop.run_in_executor to run a function in another thread and yield from it to get the result.

Or an alternative to way to do an http get async

async with aiohttp.ClientSession() as session:
        async with session.get(url, headers=HEADERS, params=params) as resp:
            data = await resp.json()

Upvotes: 1

Related Questions