RabbitMQ Pika和Django通道websocket

RabbitMQ Pika和Django通道websocket,django,rabbitmq,django-channels,pika,Django,Rabbitmq,Django Channels,Pika,我第一次使用Django频道和RabbitMQ pika。我正在尝试从RabbitMQ队列消费。我正在使用Django通道AsyncConsumer将其分组发送给websocket中连接的每个人 用户类型1:可以创建任务 用户类型2:可以接受任务 用例:当用户类型1创建任务时,它将在rabbitmq中发布。当它从队列中使用时,它必须被组发送到前端。当用户类型2接受任务时,用户类型2的其他实例无法接受相同的任务,我们再次从队列中消费,并将队列中的下一个任务发送给所有人 我使用sync\u to\u

我第一次使用Django频道和RabbitMQ pika。我正在尝试从RabbitMQ队列消费。我正在使用Django通道AsyncConsumer将其分组发送给websocket中连接的每个人

用户类型1
:可以创建任务

用户类型2
:可以接受任务

用例:当
用户类型1
创建任务时,它将在rabbitmq中发布。当它从队列中使用时,它必须被组发送到前端。当
用户类型2
接受任务时,
用户类型2
的其他实例无法接受相同的任务,我们再次从队列中消费,并将队列中的下一个任务发送给所有人

我使用
sync\u to\u async
在不同的线程中创建了连接,并将其从回调函数添加到内存中的列表中。 只要有人接受,我就把它从列表中弹出并确认队列

class AcceptTaskConsumer(AsyncConsumer):
    body = [] #IN MEMORY LIST 
    delivery = {} #To store ack delivery_tag 


    async def websocket_connect(self, event):
        print("AcceptTaskConsumer connected", event)
        AcceptTaskConsumer.get_task() #STARTS Queue listener in new thread
        self.room_group_name = "user_type_2"
        await self.channel_layer.group_add(
            self.room_group_name,
            self.channel_name
        )

        await self.send({
            "type": "websocket.accept"
        })

    async def websocket_receive(self, event):
        if event["text"] == "Hi": #If connecting first time
            if AcceptTaskConsumer.body:
                await self.channel_layer.group_send(
                    self.room_group_name,
                    {
                        "type": "message",
                        "text": AcceptTaskConsumer.body[0]["body"]
                    }
                )
            else:
                await self.channel_layer.group_send(
                    self.room_group_name,
                    {
                        "type": "message",
                        "text": "No New Tasks"
                    }
                )

        else: #When someone accepts a task-> ack and send next task in queue
            print(json.loads(event["text"])["id"])
            AcceptTaskConsumer.channel.basic_ack(delivery_tag=AcceptTaskConsumer.delivery[json.loads(event["text"])["id"]])
            AcceptTaskConsumer.delivery.pop(json.loads(event["text"])["id"])
            AcceptTaskConsumer.body.pop(0)
            await self.channel_layer.group_send(
                self.room_group_name,
                {
                    "type": "message",
                    "text": "No New Tasks"
                }
            )

            if AcceptTaskConsumer.body:
                await self.channel_layer.group_send(
                    self.room_group_name,
                    {
                        "type": "message",
                        "text": AcceptTaskConsumer.body[0]["body"]
                    }
                )

    async def message(self, event):
        await self.send({
            "type": "websocket.send",
            "text": event["text"]
        })

    @classmethod
    @sync_to_async
    def get_task(cls): #pika consumer
        cls.connection = pika.BlockingConnection(
            pika.ConnectionParameters(host='localhost'))
        cls.channel = cls.connection.channel()

        cls.channel.queue_declare(queue='task_', arguments={"x-max-priority": 3})

        cls.channel.basic_consume(
            queue='task_', on_message_callback=AcceptTaskConsumer.callback, auto_ack=False)
        cls.channel.start_consuming()

    @classmethod
    def callback(cls, ch, method, properties, body):
        task_obj = {"body": json.dumps(body.decode("utf-8")),
                    "delivery_tag": method.delivery_tag}
        AcceptTaskConsumer.body.append(task_obj)
        AcceptTaskConsumer.delivery[json.loads(json.loads(task_obj["body"]))["id"]] = method.delivery_tag
        cls.channel.stop_consuming()

    async def websocket_disconnect(self, event):
        print(event)
        await self.send({
            "type": "websocket.close"
        })

        await self.channel_layer.group_discard(
            self.room_group_name,
            self.channel_name
        )
我很确定这不是正确的方法,因为它没有按预期工作

我经常遇到像这样的错误

  • 169个渠道中有39个在集团交付中产能过剩
  • pika.exceptions.StreamLosError:流连接丢失:断开管道错误(32,“断开管道”)
我也试着运行队列侦听器。没用。
有没有人对此有过想法?是否有更好的方法解决此问题?

您应该将rabitMQ消费逻辑移出websocket消费程序

只要有一个运行Rabbit Consumer的django,该Consumer就可以从RabbitMQ获取消息,然后使用
send_group
将它们通过组发送到通道

如果使用django命令,则需要调用send_group,请参阅

从channels.layers导入获取通道层
通道层=获取通道层()
异步到同步(
信道\层组\发送
)(
“用户类型2”,
{“类型”:“消息”,“消息”:123}
)


然后,在websocket使用者中,您应该订阅用户希望/有权获得的组。

您应该将rabitMQ消费逻辑移出websocket使用者

只要有一个运行Rabbit Consumer的django,该Consumer就可以从RabbitMQ获取消息,然后使用
send_group
将它们通过组发送到通道

如果使用django命令,则需要调用send_group,请参阅

从channels.layers导入获取通道层
通道层=获取通道层()
异步到同步(
信道\层组\发送
)(
“用户类型2”,
{“类型”:“消息”,“消息”:123}
)


然后,在websocket使用者中,您应该订阅用户想要/有权限获得的组。

感谢您的发布如果我配置了自定义命令,它会在其他线程中运行吗?因为线程似乎是这里的问题。如果你知道更好的方法。我是earsAlso,如果我们在不同的命令中运行它,我们如何将消息传递给发送组?我们需要一个第三方脏存储,对吗?(我已经更新了awser,包括如何从您的命令中发送到组)谢谢发布。如果我配置了自定义命令,它会在不同的线程中运行吗?因为线程似乎是这里的问题。如果你知道更好的方法。我是earsAlso,如果我们在不同的命令中运行它,我们如何将消息传递给发送组?我们需要一个第三方脏存储,对吗?(我已经更新了awser,包括如何从命令中发送到组)