Django Channels 2.0 channel_layers无法通信

时间:2018-02-02 20:16:47

标签: python django websocket celery django-channels

所以我一直在迁移使用Django Channels 1.x的服务器 - > 2.X +

原始设计会使用getAFTreeTask.delay(message.reply_channel.name)向celery发送任务,并且可以访问channel_name它可以异步回复

from celery import task
from channels import Channel

@task
def getAFTreeTask(channel_name):
    tree = Request().cache_af_tree()
    Channel(channel_name).send({
        "text": json.dumps({
            "channel": "AF_INIT",
            "payload": tree
        })
    })

现在,由于各种原因,我已将服务器迁移到Channels 2.x +。根据文件

class Consumer(JsonWebsocketConsumer):

     def connect(self):
        print("Client Connected: ", self.channel_name)
        self.accept()

    def receive_json(self, content, **kwargs):
        print(content)
        parse_request(self.channel_name, content)

    def disconnect(self, content):
        print(content)

    def chat_message(self, event):
        print("Entered reply channel")
        print(event)

如果响应有权访问self.send_json()或{{1} }对于其他通用消费者,所以我假设我的所有设置都是正确的,我的问题是当我尝试使用通道层发送内容时(例如根据https://channels.readthedocs.io/en/latest/topics/channel_layers.html#single-channels

self.send()

我得到了

编辑(完整堆栈跟踪):

from channels.layers import get_channel_layer
from asgiref.sync import AsyncToSync

def parse_request(channel_name, content):

    print("parsed ", channel_name, content)
    channel_layer = get_channel_layer()
    AsyncToSync(channel_layer.send)(channel_name, {
        "type": "chat.message",
        "text": "Hello there!",
    })

如果我没有使用 2018-02-02 18:28:35,984 ERROR Exception inside application: There is no current event loop in thread 'Thread-3'. File "/usr/lib/python3.5/asyncio/tasks.py", line 241, in _step result = coro.throw(exc) File "/home/chris/Env/myapp/lib/python3.5/site-packages/channels/consumer.py", line 51, in __call__ await await_many_dispatch([receive, self.channel_receive], self.dispatch) File "/home/chris/Env/myapp/lib/python3.5/site-packages/channels/utils.py", line 48, in await_many_dispatch await dispatch(result) File "/home/chris/Env/myapp/lib/python3.5/site-packages/asgiref/sync.py", line 81, in inner return await async_func(*args, **kwargs) File "/home/chris/Env/myapp/lib/python3.5/site-packages/asgiref/sync.py", line 65, in __call__ return await asyncio.wait_for(future, timeout=None) File "/usr/lib/python3.5/asyncio/tasks.py", line 373, in wait_for return (yield from fut) File "/usr/lib/python3.5/asyncio/futures.py", line 361, in __iter__ yield self # This tells Task to wait for completion. File "/usr/lib/python3.5/asyncio/tasks.py", line 296, in _wakeup future.result() File "/usr/lib/python3.5/asyncio/futures.py", line 274, in result raise self._exception File "/usr/lib/python3.5/concurrent/futures/thread.py", line 55, in run result = self.fn(*self.args, **self.kwargs) File "/home/chris/Env/myapp/lib/python3.5/site-packages/asgiref/sync.py", line 74, in thread_handler raise e File "/home/chris/Env/myapp/lib/python3.5/site-packages/asgiref/sync.py", line 72, in thread_handler self.func(*args, **kwargs) File "/home/chris/Env/myapp/lib/python3.5/site-packages/channels/consumer.py", line 93, in dispatch handler(message) File "/home/chris/Env/myapp/lib/python3.5/site-packages/channels/generic/websocket.py", line 40, in websocket_receive self.receive(text_data=message["text"]) File "/home/chris/Env/myapp/lib/python3.5/site-packages/channels/generic/websocket.py", line 104, in receive self.receive_json(self.decode_json(text_data), **kwargs) File "./MYAPP/API/consumers.py", line 13, in receive_json parse_api_request(self.channel_name, content) File "./MYAPP/API/api_request.py", line 16, in parse_api_request AsyncToSync(channel_layer.send)(channel_name, { File "/home/chris/Env/myapp/lib/python3.5/site-packages/asgiref/sync.py", line 17, in __init__ self.main_event_loop = asyncio.get_event_loop() File "/usr/lib/python3.5/asyncio/events.py", line 632, in get_event_loop return get_event_loop_policy().get_event_loop() File "/usr/lib/python3.5/asyncio/events.py", line 578, in get_event_loop % threading.current_thread().name) There is no current event loop in thread 'Thread-3'. 我得到(根据我不应该做的文件,只是为了检查

AsyncToSync
当我完全遵循指南时我不明白,我也尝试从芹菜任务(一个单独的线程)回复并没有得到相同的错误但没有任何反应,芹菜日志只是说任务完成了,但我没有得到答复。

另外,尝试直接通过

发送响应
2018-02-02 18:34:27,965 WARNING  ./MYAPP/API/api_request.py:18: builtins.RuntimeWarning: coroutine 'RedisChannelLayer.send' was never awaited

从内部和外部线程获得相同的非结果....

是否有人能够通过AsyncToSync(channel_layer.send)(channel_name, { "type": "websocket.send", "text": "Hello there!", }) 对象之外的channel_layers发送。

FYI my settings.py

Consumers

1 个答案:

答案 0 :(得分:6)

来自Andres Godwin的reply之后:

我发现这是asgiref中的错误< 2.1.3,通过升级SyncToAsync / AsyncToSync的返回值已得到修复!

所以我的工作实施,对于任何有兴趣的人:

consumers.py

from channels.consumer import AsyncConsumer

class My_Consumer(AsyncConsumer):

async def websocket_connect(self, event):
    print("Connected")
    print(event)
    print(self.channel_name)
    await self.send({
        "type": "websocket.accept",
    })

async def websocket_receive(self, event):
    print("Received")
    print(event)
    parse_api_request(self.channel_name, json.loads(event['text']))

async def celery_message(self, event):
    print("Service Received")
    print(event)
    await self.send({
        "type": "websocket.send",
        "text": event["text"],
    })


task.py 

from channels.layers import get_channel_layer
from asgiref.sync import AsyncToSync


def async_send(channel_name, text):
    channel_layer = get_channel_layer()
    AsyncToSync(channel_layer.send)(
            channel_name,
            {"type": "celery.message",
             "text": json.dumps(text)
             })


def getAFTree(channel_name, message):
    getAFTreeTask.delay(channel_name, message)



@task
def getAFTreeTask(channel_name, message):
    tree = Request().cache_af_tree()
    async_send(channel_name, {
                "channel": "AF_INIT",
                "payload": tree
             })