渠道:为什么在处理结束时发送消息

时间:2020-05-29 14:46:26

标签: django django-channels channels

为什么使用同步功能get_channel_layer().send(),则在处理结束时发送消息

def external_send(channel_name, data):
    channel_layer = get_channel_layer()
    send_sync = async_to_sync(channel_layer.send)
    send_sync(
        channel_name,
        {
            "type": "send_json",
            "message": {"datetime": datetime.datetime.now().isoformat(), **data},
        },
    )

按预期在消费者工作中使用self.send()

这是我用于测试的消费者类别:

class TestConsumer(JsonWebsocketConsumer):
    def connect(self):
        self.accept()

    def disconnect(self, close_code):
        pass

    def receive_json(self, content, **kwargs):
        logger.debug(f"RECEIVE {content}")
        self.send_json(
            {
                "id": 1,
                "text": "Before sleep: self.send_json",
                "datetime": datetime.datetime.now().isoformat(),
            }
        )
        external_send(
            self.channel_name, {"id": 2, "text": "Before sleep external_send"}
        )
        sleep(10)  # Simuleting long processing
        self.send_json(
            {
                "id": 3,
                "text": "After sleep: self.send_json",
                "datetime": datetime.datetime.now().isoformat(),
            }
        )
        super().receive_json(content, **kwargs)
        logger.debug("END")

我在前端收到订单

  • {id:1,文本:“睡眠前:self.send_json”,日期时间:“ 2020-05-29T14:30:58.226545”}
  • {id:3,文本:“入睡后:self.send_json”,日期时间:“ 2020-05-29T14:31:03.244865”}
  • {id:2,文本:“ before sleep external_send”,日期时间:“ 2020-05-29T14:30:58.230164”}

enter image description here

1 个答案:

答案 0 :(得分:0)

答案是,每个渠道使用者都有自己的小运行循环。一次只能处理一个事件。这个单一的运行循环既用于从客户端(通过ws)接收的消息,也用于通过通道层上的组发送事件处理的消息。

如果您的receive_json方法正在睡眠,则正在睡眠循环,因此不会发生其他任何事情。 receive_json需要先完成,然后才能处理通过通道层发送的任何消息。

查看您的代码,还需要指出其他几点

同步sleep

如果您确实需要sleep使用方法从不进行同步,则这将使您的整个 python程序进入睡眠状态(一切都会进入睡眠状态) 。

使用异步使用者,您可以await asyncio.sleep(20),然后sleep对该单个使用者的运行循环,其他websocket连接等将继续运行。对于任何其他长期运行的任务,也应如此,您应该使用异步使用者,然后使用异步线程池await来运行这些长期运行的任务。

您不应尝试直接将发送到send_json方法的分组。

您应该在使用者handle_message上创建一个方法,此方法可以调用send_json,并且您的组发送的消息应该发送类型为handle.message的消息。