我创建了一个简单的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!')
所以发生的是,我可以看到正在打印到控制台的数据,但是如果我尝试离开该页面并到达网站的其他部分,则该页面将在加载时卡住。谁能帮我解决这个问题?
答案 0 :(得分:1)
您可能想在这里做两件事。
您遇到的问题pubsub.listen():
将永远循环(永远不会停止)。因此,您的消费者将永远不会继续,并且能够处理更多消息。
由于(至少在本示例中)似乎总是使用静态值(而不取决于用户的请求)来访问redis,所以最好在使用者之外进行此订阅。 (在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)
然后在打印的管理命令中,您可以使用
发送消息
async_to_sync(channel_layer.group_send)(
"echo_group",
{"type": "on.message", "rate":Rate, "quantity": Quantity, "symbol": Symbol, "order": Order},
)
仅当您期望每个Websocket连接的订阅不同时,才应该这样做。 (例如,您使用的是url / query / headers中的值,或者仅在用户使用给定的过滤器值向客户发送ws消息时才订阅)。
由于以下几个原因,这样做LOT
比较复杂:
Redis将无法处理与它的websocket连接一样多的打开连接。
您需要设置一个嵌套的异步任务,该任务可以处理来自redis的事件,从而不会阻塞其他使用者。
如果您仍然需要此功能,我很乐意使用解决方案来更新答案(但警告会很长)。