等待 django 通道消费者中的 websocket 连接

问题描述 投票:0回答:1

我正在使用 Celery 和 Channels 在另一个用户在服务器上执行某个操作时通知用户。在浏览器上,我使用 WebSockets 将用户连接到消费者。不幸的是,如果事件发生时用户不在线(这意味着 WebSocket 已关闭),他们将错过我存储在数据库中的通知。如何检查用户是否仍然连接并发送信息,或者如果没有,则等待建立连接然后发送通知?

消费者.py


class MyConsumer(AsyncWebsocketConsumer):
    async def connect(self):
        self.user_inbox = f'inbox_{self.scope["user"].username}'
        # Check if user is anonymous and close the connection when true
        if self.scope["user"].is_anonymous:
            await self.close()
        self.connected_user = self.scope["user"]
        self.room_name = self.scope["url_route"]["kwargs"]["room_name"]
        self.room_group_name = "chat_%s" % self.room_name
        # Join room group

        await self.channel_layer.group_add(self.room_group_name, self.channel_name)

        await self.accept()

    async def disconnect(self, close_code):
        # Leave room group
        await self.channel_layer.group_discard(self.room_group_name, self.channel_name)


    async def chat_message(self, event):
        """FIRES WHEN MESSAGE IS SENT TO LAYERS"""
        event_dict = {
            "message_header": event["message_header"],
            "message_body": event["message_body"],
            "sender": event["sender"],
            "subject": event["subject"],
        }
        # Send message to WebSocket
        await self.send(text_data=json.dumps(event_dict))

任务.py


@shared_task
def send_notification_to_ws(ws_channel, ws_event):
    channel_layer = get_channel_layer()
    async_to_sync(channel_layer.group_send)(ws_channel, ws_event)

信号.py

ws_event = {
            "type": "chat_message",
            "message_header": message_header,
            "message_body": message_body,
            "sender": sender.username,
            "subject": subject,
        }
        ws_channel = "chat_%s" % recipient.username
        send_notification_to_ws.delay(ws_channel=ws_channel, ws_event=ws_event)

我一直在考虑是否有一种方法可以检查用户是否存在于群组频道层中,因为我正在为特定用户创建群组频道。这意味着该组将仅由一个用户组成。并且可能使用上面的信息运行一个循环,直到用户可用并发送信息。我不确定这是否可能或者它是否优雅解决这个问题的方法。只是想法????? 请帮忙。

注意:用户在线时一切正常。

django websocket django-views channel django-channels
1个回答
0
投票

还有另一种方法,但需要对代码和逻辑进行一些重构。

我喜欢将 websocket 代码视为对从前端客户端发送给它的命令的反应。在这种情况下,我们需要另一个应用程序(consumers.py 中的一个

AsyncWebsocketConsumer
类)来帮助管理这个应用程序。考虑以下应用程序。

当用户第一次连接时接收命令的应用程序能够将该用户的 ID 保存到连接列表(或生成一个新的)。该 userID 告诉我们如何连接到我们将要使用的 websocket 中的用户。如果该用户能够连接,如果房间可用,那么我们会发回一条消息,告诉它运行 javascript 函数,如果需要的话,使用他们的用户 ID 连接到 websocket。每 15 秒或 x 时间量,我们在第一个 websocket 上 ping 该用户 ID 并等待编程到前端的响应。如果用户响应,我们什么都不做,如果他们不响应,我们将他们从我们连接的用户列表中删除。

然后,在我们最初的 websocket 上,我们可以简单地有一个应用程序来搜索这个已连接用户列表,并向他们发送您希望他们从数据库中读取的信息字符串。您可能需要在此处添加到您的数据库条目,并确保您跟踪一个

BooleanField
,无论该字符串是否已发送。您可以将其默认为 True,然后在发送时在 websocket 函数中将其设置为 False(并且仅在其为 True 时才发送)。

这里要注意的一点是,你说过你将这些信息存储在你的数据库中,如果你想在像你的 websocket 消费者这样的异步函数中访问它,请确保在 consumers.py 顶部导入装饰器后使用装饰器

@database_sync_to_async

from channels.db import database_sync_to_async
© www.soinside.com 2019 - 2024. All rights reserved.