使用信号时如何避免Django通道运行时错误?

时间:2018-12-12 04:39:52

标签: python-asyncio django-channels

我有一个django服务(例如'brisbane'),当使用以下通道和信号保存数据库模型时,该服务会将更新推送到客户端浏览器:

def invalidated_serialized_model_receiver(self, sender, **kwargs):
    ...
    async_to_sync(get_channel_layer().group_send)(name, update)

这有效并提供了实时更新。

'brisbane'现在需要与另一个服务(相同的代码)'sydney'进行交互,以便可以根据sydney's数据的变化实时进行类似的实时更新。这使用了在另一个进程中运行的使用者,看起来像这样:

async def remote_site_consume(site):
    socket_url = site.urn(protocol='ws', resource_name='/ws/watch/')
    async with websockets.connect(socket_url) as websocket:
        await websocket.send(json.dumps({'type': 'watch_messages'}))
        ...
        async for event in websocket:
            event = json.loads(event)
            await get_event_handler(event)(site, websocket, event)

信号可能会从发生问题的事件处理程序内合法发送。发生这种情况时,它将引发RuntimeError

  

'您不能在与异步事件循环相同的线程中使用AsyncToSync   -只需直接等待异步功能即可。'

我不能只使用await,因为信号也是从没有事件循环的线程发送的。

1 个答案:

答案 0 :(得分:0)

我正在尝试用此替代async_to_sync的方法,该方法似乎至少在本地测试中有效:

def invalidated_serialized_model_receiver(self, sender, **kwargs):
    ...
    create_or_use_loop(self.channel_layer.group_send(name, update))


def create_or_use_loop(awaitable):
    try:
        event_loop = asyncio.get_event_loop()
    except RuntimeError:
        event_loop = None

    if event_loop and event_loop.is_running():
        event_loop.call_soon_threadsafe(event_loop.create_task, awaitable)
    else:
        loop = asyncio.new_event_loop()
        asyncio.set_event_loop(loop)
        try:
            loop.run_until_complete(awaitable)
        finally:
            loop.close()
            asyncio.set_event_loop(event_loop)

这感觉很笨拙。