Hello,
I have a worker process that uses async_to_sync(group_send) to send messages to my Channels consumers. The worker process is a simple long-running synchronous loop (not based on Django Channels) that is started via a Django management command.
When I use runserver and the in-memory channel layer, performance is great. But when I use channels_redis in production, each call to group_send takes 2 seconds, because each time it needs to create a new redis connection. Here is the call stack:
File "c:\my_project\core\my_project\channels\utils.py", line 14, in sync_group_send_wrapper
return _sync_group_send(group, {'type': type, **event})
File "c:\my_project\ve-dj2\lib\site-packages\asgiref\sync.py", line 79, in __call__
return call_result.result()
File "C:\Users\user\AppData\Local\Programs\Python\Python37-32\lib\concurrent\futures\_base.py", line 428, in result
return self.__get_result()
File "C:\Users\user\AppData\Local\Programs\Python\Python37-32\lib\concurrent\futures\_base.py", line 384, in __get_result
raise self._exception
File "c:\my_project\ve-dj2\lib\site-packages\asgiref\sync.py", line 98, in main_wrap
result = await self.awaitable(*args, **kwargs)
File "c:\my_project\ve-dj2\lib\site-packages\channels_redis\core.py", line 625, in group_send
async with self.connection(self.consistent_hash(group)) as connection:
File "c:\my_project\ve-dj2\lib\site-packages\channels_redis\core.py", line 839, in __aenter__
self.conn = await self.pool.pop()
File "c:\my_project\ve-dj2\lib\site-packages\channels_redis\core.py", line , in pop
conns.append(await aioredis.create_redis(**self.host, loop=loop))
This is happening because the connection is deleted after each call to async_to_sync:
File "c:\my_project\core\my_project\channels\utils.py", line 14, in sync_group_send_wrapper
return _sync_group_send(group, {'type': type, **event})
File "c:\my_project\ve-dj2\lib\site-packages\asgiref\sync.py", line 71, in __call__
loop.close()
File "c:\my_project\ve-dj2\lib\site-packages\channels_redis\core.py", line 32, in _wrapper
self.run_until_complete(pool.close_loop(self))
File "C:\Users\user\AppData\Local\Programs\Python\Python37-32\lib\asyncio\base_events.py", line 579, in run_until_complete
return future.result()
File "c:\my_project\ve-dj2\lib\site-packages\channels_redis\core.py", line , in close_loop
del self.conn_map[loop]
When async_to_sync is called from a synchronous Django view, the connection is NOT deleted. That's because in my worker process, self.main_event_loop.is_running() is False, but in my Django views, it's True. That affects this if-statement in async_to_sync.__call__:
if not (self.main_event_loop and self.main_event_loop.is_running()):
# Redis connection gets deleted inside here...
So, how could I solve this? This may be an obvious question but I don't know asyncio well; I just want to get some guidance before I spend too much time looking in the wrong direction.
Thank you!