如何使用ChannelNameRouter在Worker和WebSocket(Django和Channels2.x)之间进行通信?

yuvru6vn  于 2023-05-29  发布在  Go
关注(0)|答案(2)|浏览(125)

我正在尝试设置一个使用django2.0.2和channels2.1.1的应用程序。我想实现的是使用一个后台/工人任务来执行一些将产生数据的工作,这些数据应该动态地出现在网站上。我的问题,主要与渠道有关,是:如何正确建立连接到WebSocket的worker和consumer之间的通信?
下面是一个简单的例子来强调这个问题:这个想法是用户触发worker,worker产生一些数据并通过通道层将其发送到连接到WebSocket的消费者。

#routing.py
from channels.routing import ChannelNameRouter, ProtocolTypeRouter, URLRouter
from channels.auth import AuthMiddlewareStack
from django.urls import path
from testApp.consumers import *

application = ProtocolTypeRouter({
    "websocket":AuthMiddlewareStack(
        URLRouter([
            path("wspath",TestConsumer),
        ]),
    ),
    "channel":ChannelNameRouter({
        "test_worker": TestWorker,
    }),
})

消费者:

#consumers.py
from channels.consumer import SyncConsumer
from channels.generic.websocket import WebsocketConsumer
from asgiref.sync import async_to_sync

class TestConsumer(WebsocketConsumer):
    def websocket_connect(self,message):
        async_to_sync(self.channel_layer.group_add)("testGroup",self.channel_name)
        self.connect()
        #I understand this next part is a bit weird, but I figured it 
        #is the most concise way to explain my problem
        async_to_sync(self.channel_layer.group_send)(
            "testGroup",
            {
                'type':"echo_msg",
                'msg':"sent from WebsocketConsumer",
            })

    def echo_msg(self, message):
        print("Message to WebsocketConsumer", message)

class TestWorker(SyncConsumer):
    def triggerWorker(self, message):
        async_to_sync(self.channel_layer.group_add)("testGroup",self.channel_name)
        async_to_sync(self.channel_layer.group_send)(
            "testGroup",
            {
                'type':"echo_msg",
                'msg':"sent from worker",
            })

    def echo_msg(self, message):
        print("Message to worker ", message)

风景

#views.py
from django.shortcuts import render
import channels.layers
from asgiref.sync import async_to_sync

def index(request):
    if request.method == "POST":
        channel_layer = channels.layers.get_channel_layer()
        async_to_sync(channel_layer.send)('test_worker',{
            'type':'triggerWorker',
        })
    return render(
        request,
        "index.html",
        {})

HTML:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <script>
        console.log('ws://' + window.location.host)
        var socket = new WebSocket(
            'ws://' + window.location.host + "/wspath"
        );
    </script>
</head>
<div>Click to run worker</div>
<body>
    <form action="" method="POST">
        {% csrf_token %}
        <button type="submit">Start</button>   
    </form>
</body>

现在,当我通过执行(在单独的控制台中)来运行它时

python3 manage.py runserver

python3 manage.py runworker test_worker

然后触发worker,runserver控制台输出:
给WebsocketConsumer的消息“type”:'echo_msg',' msg':'sent from WebsocketConsumer'}
其中runworker控制台输出:
给员工的消息“类型”:'echo_msg',' msg':'发送自工作人员'}
给员工的消息“类型”:'echo_msg',' msg':'sent from WebsocketConsumer'}
所以我可以发送worker-> worker,WebsocketConsumer -> WebsocketConsumer,WebsocketConsumer -> worker。
根据我的理解(这显然是错误的),应该还有一个消息工作者-> WebsocketConsumer,因为我将两者都添加到了“testGroup”中。
所以,我的问题是为什么WebsocketConsumer没有从worker接收任何东西(这是我感兴趣的,最终与javaScript建立通信)?或者,换句话说,为什么我只能从WebsocketConsumer向worker发送东西,而不是相反?

gstyhher

gstyhher1#

我在运行你的代码。我可以看到一切都在工作。
您在POST上有初始消息-正在工作-您将其添加到组中。当WebSocket连接时,它会向worker发送一条消息。您可以在runworker终端中看到它。这将把它返回给您的消费者,并在运行runserver的终端中打印出来。要将其返回到Web浏览器,您需要编写:
def echo_msg(self, message): print("Message to WebsocketConsumer", message) self.send(json.dumps(message))
在Chrome中打开您的开发者工具,看看它是否回来了。进入网络>选择WebSocket连接>然后点击frames。
顺便说一句,你不需要一遍又一遍地将测试工作者添加到同一个组。这个工人总是在跑。
另一个BTW:如果您的组将为所有用户命名为相同的名称,则不需要将您的worker添加到组中。您可以通过路由名直接向worker发送消息(send而不是group_send)。worker可以将消息发送回组,而无需将其添加到组。您只需要将WebSocket消费者添加到组中。
此外,如果您不希望多个用户看到相同的消息,则根本不需要组。只需将消息发送给具有通道名称(self.channel_name)的worker,然后将其发送回。
你也可能希望使用json消费者而不是自己解析消息,但这取决于你。

lskq00tm

lskq00tm2#

您的WebSocket从未被使用。您正在从视图向工作者发送消息-而不是从消费者向工作者发送消息。当您向视图发送数据时,视图正在发送该消息。
您在JavaScript中的URL是/wspath/,您在消费者上注册的URL是chat/stream。WebSocket从未连接。
此外,您的工作人员将被添加到同一组一遍又一遍与您目前的设置。您只需要将工作线程添加到组中一次。

相关问题