Django страница каналов застряла при загрузке - PullRequest
1 голос
/ 09 апреля 2020

Я создал простого потребителя Django Channels, который подключается к каналу Redis и получает некоторые данные из этого канала. Я хочу отправить эти данные во внешний интерфейс.

Потребитель может подключиться к потребитель и получает данные; проблема в том, что если я попытаюсь загрузить страницу, когда пользователь работает, страница застрянет при загрузке. Я уверен, что это происходит потому, что соединение с каналом Redis является блокирующей операцией, или это может быть проблемой с потоками. Я новичок в этой концепции, поэтому я решил задать вопрос.

Вот мой потребитель:

class EchoConsumer(AsyncConsumer):

    async def websocket_connect(self, event):
        self.send({
                'type': 'websocket.accept'
            })

        self.receive(event)

    def receive(self, event):
        redis_url = 'redis://localhost:6379/0'
        connection = redis.StrictRedis.from_url(redis_url, decode_responses=True)
        channel = 'TEST'
        params = urllib.parse.parse_qs(self.scope.get('query_string', b'').decode('utf-8'))

        pubsub = connection.pubsub(ignore_subscribe_messages=True)
        pubsub.subscribe(channel)

        for message in pubsub.listen():

            # self.send({
            #   'type': 'websocket.send',
            #   'text': message['data'],
            # })

            print(message['data'])


    async def websocket_disconnect(self, event):
        print('DISCONNECTED!')

Итак, что я могу видеть, как распечатываются данные на моей консоли, но если я попытаюсь покинуть эту страницу и перейти к другой части моего сайта, страница застрянет при загрузке. Может кто-нибудь помочь мне исправить это?

1 Ответ

1 голос
/ 10 апреля 2020

Есть 2 вещи, которые вы могли бы попытаться сделать здесь.

Однажды подписавшись и отправив эту информацию на все открытые соединения

, у вас возникла проблема pubsub.listen(): l oop навсегда (никогда не останавливаясь). Таким образом, ваш потребитель никогда не будет продолжать и сможет обрабатывать больше сообщений.

Поскольку (по крайней мере, в этом примере) похоже, что вы всегда нажимаете на redis со значениями stati c (независимо от запроса от пользователь) вам лучше делать эту подписку за пределами вашего потребителя. (в команде django https://docs.djangoproject.com/en/3.0/howto/custom-management-commands/)

Затем вы можете получить эту команду, а затем отправить эти сообщения по канальному уровню вашим подписанным потребителям.

это будет Сделайте так, чтобы ваш потребитель выглядел следующим образом

class EchoConsumer(AsyncJsonWebsocketConsumer):
    async def on_message(self, message):
        await self.send_json(message)

, затем в вашей команде управления instread of print вы можете отправить сообщение, используя


async_to_sync(channel_layer.group_send)(
        "echo_group",
        {"type": "on.message", "rate":Rate, "quantity": Quantity, "symbol": Symbol, "order": Order},
    )

Подписавшись один раз на каждое открытое соединение

Это следует делать только в том случае, если вы ожидаете, что подписка будет отличаться для каждого подключения к веб-сокету. (например, вы используете значение в URL-адресе / запросе / заголовке или подписываетесь только тогда, когда пользователь отправляет сообщение ws вашему потребителю с заданным значением фильтра).

Выполнение этого является LOT более сложным для несколько причин:

  1. Redis не будет обрабатывать столько открытых соединений с ним, сколько у вас могут быть подключения через веб-сокет.

  2. Вам необходимо настроить вложенная asyn c задача, которая может обрабатывать события от redis таким образом, чтобы они не блокировали остальную часть потребителя.

Если вам все еще нужна эта функция, я рад обновить ответ решением (но предупреждаю, что это будет долго).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...