question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Cannot test synchronous consumer that includes async_to_sync

See original GitHub issue

I am having a problem calling async_to_sync from python manage.py tests. The relevant code is

class MyHandler(SyncConsumer):

    def websocket_connect(self, event):
        self.send({ "type": "websocket.accept"})
        async_to_sync(self.channel_layer.group_add('grpup', self.channel_name))

Test looks like this – I use asynctest because I don’t want this to be the only test in my project that uses pytest syntax.

class ChannelTests(asynctest.TestCase):

    async def test_websockets(self):
        communicator = WebsocketCommunicator(MyHandler, path)
        connected, subprotocol = await communicator.connect()
        self.assertTrue(connected)

When I run this, I get RuntimeError: You cannot use AsyncToSync in the same thread as an async event loop - just await the async function directly. But I’m actually not sure it ever gets to my async_to_sync call. Looking at the call stack, it seems to bomb on the previous line:

Traceback (most recent call last):
  File "/Users/jonathanstray/anaconda/lib/python3.5/site-packages/asynctest/case.py", line 297, in run
    self._run_test_method(testMethod)
  File "/Users/jonathanstray/anaconda/lib/python3.5/site-packages/asynctest/case.py", line 354, in _run_test_method
    self.loop.run_until_complete(result)
  File "/Users/jonathanstray/anaconda/lib/python3.5/site-packages/asynctest/case.py", line 224, in wrapper
    return method(*args, **kwargs)
  File "/Users/jonathanstray/anaconda/lib/python3.5/asyncio/base_events.py", line 387, in run_until_complete
    return future.result()
  File "/Users/jonathanstray/anaconda/lib/python3.5/asyncio/futures.py", line 274, in result
    raise self._exception
  File "/Users/jonathanstray/anaconda/lib/python3.5/asyncio/tasks.py", line 241, in _step
    result = coro.throw(exc)
  File "/Users/jonathanstray/PycharmProjects/cjworkbench/server/tests/test_websockets.py", line 26, in test_websockets
    connected, subprotocol = await communicator.connect()
  File "/Users/jonathanstray/anaconda/lib/python3.5/site-packages/channels/testing/websocket.py", line 33, in connect
    response = await self.receive_output(timeout)
  File "/Users/jonathanstray/anaconda/lib/python3.5/site-packages/asgiref/testing.py", line 66, in receive_output
    self.future.result()
  File "/Users/jonathanstray/anaconda/lib/python3.5/asyncio/futures.py", line 274, in result
    raise self._exception
  File "/Users/jonathanstray/anaconda/lib/python3.5/asyncio/tasks.py", line 241, in _step
    result = coro.throw(exc)
  File "/Users/jonathanstray/anaconda/lib/python3.5/site-packages/channels/consumer.py", line 54, in __call__
    await await_many_dispatch([receive, self.channel_receive], self.dispatch)
  File "/Users/jonathanstray/anaconda/lib/python3.5/site-packages/channels/utils.py", line 48, in await_many_dispatch
    await dispatch(result)
  File "/Users/jonathanstray/anaconda/lib/python3.5/site-packages/asgiref/sync.py", line 110, in __call__
    return await asyncio.wait_for(future, timeout=None)
  File "/Users/jonathanstray/anaconda/lib/python3.5/asyncio/tasks.py", line 373, in wait_for
    return (yield from fut)
  File "/Users/jonathanstray/anaconda/lib/python3.5/asyncio/futures.py", line 361, in __iter__
    yield self  # This tells Task to wait for completion.
  File "/Users/jonathanstray/anaconda/lib/python3.5/asyncio/tasks.py", line 296, in _wakeup
    future.result()
  File "/Users/jonathanstray/anaconda/lib/python3.5/asyncio/futures.py", line 274, in result
    raise self._exception
  File "/Users/jonathanstray/anaconda/lib/python3.5/concurrent/futures/thread.py", line 55, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/Users/jonathanstray/anaconda/lib/python3.5/site-packages/channels/db.py", line 13, in thread_handler
    return super().thread_handler(loop, *args, **kwargs)
  File "/Users/jonathanstray/anaconda/lib/python3.5/site-packages/asgiref/sync.py", line 125, in thread_handler
    return self.func(*args, **kwargs)
  File "/Users/jonathanstray/anaconda/lib/python3.5/site-packages/channels/consumer.py", line 99, in dispatch
    handler(message)
  File "/Users/jonathanstray/PycharmProjects/cjworkbench/server/websockets.py", line 36, in websocket_connect
    self.send({ "type": "websocket.accept"})
  File "/Users/jonathanstray/anaconda/lib/python3.5/site-packages/channels/consumer.py", line 107, in send
    self.base_send(message)
  File "/Users/jonathanstray/anaconda/lib/python3.5/site-packages/asgiref/sync.py", line 34, in __call__
    "You cannot use AsyncToSync in the same thread as an async event loop - "
RuntimeError: You cannot use AsyncToSync in the same thread as an async event loop - just await the async function directly.

This is on OS X / django 1.11 / channels 2.0.2

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:1
  • Comments:15 (5 by maintainers)

github_iconTop GitHub Comments

4reactions
matthiaskcommented, Mar 3, 2018

Maybe not directly related, but there’s probably a problem with your code. The line async_to_sync(self.channel_layer.group_add('grpup', self.channel_name)) should be async_to_sync(self.channel_layer.group_add)('grpup', self.channel_name) instead. You want to convert the group_add method into a synchronous version and call it. See https://channels.readthedocs.io/en/latest/topics/channel_layers.html#synchronous-functions

2reactions
Otrebuscommented, May 25, 2019

If an async test runs some function which in turn runs something within async_to_sync you can wrap that function in sync_to_async to get rid of the “You cannot use AsyncToSync in the same thread as an async event loop - just await the async function directly” error.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Django Channels Error: you cannot use AsyncToSync in the ...
You cannot use AsyncToSync in the same thread as an async event loop - just await the async function directly. Here is the...
Read more >
Asynchronous support - Django documentation
Django has support for writing asynchronous (“async”) views, along with an entirely async-enabled request stack if you are running under ASGI.
Read more >
Testing — Channels 4.0.0 documentation
Testing Channels consumers is a little trickier than testing normal Django views due to their underlying asynchronous nature. To help with testing, Channels ......
Read more >
Django Channels 2.0.0 groups
This example uses WebSocket consumer, which is synchronous, and so # needs the async channel layer functions to be converted. from asgiref.sync import ......
Read more >
6 | Asynchronous chat consumer | Django Channels 2
How to use Async programming to implement asynchronous consumer ?Links - Source Code - https://github.com/aarav-tech/chat_demoFacebook ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found