Переход с Django-WSGI на ASGI/Uvicorn: проблема с синхронным вызовом функции AppConfig.ready() в асинхронном контексте
Я переключаю свои представления приложений на асинхронные вызовы, поскольку они запрашивают ряд данных из базы данных.
При запуске асинхронных представлений с сервера wsgi все работает в соответствии с ожиданиями.
Но чтобы получить реальную выгоду от асинхронного перезаписывания моего приложения, я сейчас пытаюсь запустить свое приложение как asgi-приложение вместе с Uvicorn.
asgi.py:
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'MyAppName.settings')
application = get_asgi_application()
При запуске asgi-сервера с помощью:
uvicorn MyAppName.asgi:application
В итоге я запускаю:
Только синхронная операция(сообщение) django.core.exceptions.Synchronousonly Operation: вы не можете вызвать это из асинхронного контекста - используйте поток или sync_to_async
Причина в том, что с помощью моего метода AppConfig.ready() я вызываю функцию, которая заполняет некоторые ключевые данные из базы данных в кэше.
my_app/apps.py:
class MyAppConfig(AppConfig):
name = 'my_app'
def ready(self):
"""
hook for application initialization :
is called as soon as the registry is fully populated for this app
put your startup code here
useful to run some code inside the Django appserver process
or you need to initialize something in memory, in the context of the Django app server
"""
# Reinitializing cache to enable the cached_dicts to get the right values:
cached_dicts.set_up_cache_dicts()
AppConfig.ready() по замыслу, это метод синхронизации в Django, но сервер asgi, по-видимому, требует, чтобы эти запросы к базе данных были асинхронными
Я тестировал разные способы предотвращения исключения или объявления AppConfig.ready() в качестве асинхронного метода.
В лучшем случае исключения нет, но функция кэширования не ожидается, и кэш не заполняется.
Похоже, нет никакого способа вызвать асинхронный код через AppConfig.ready().
Есть какие-нибудь идеи, как я мог бы заполнить свой кэш из базы данных во время запуска моего приложения Django в контексте asgi?
Мы обошли это ограничение, запустив асинхронную фоновую задачу (упрощенную):
def ready(self):
loop = get_running_loop()
task = loop.create_task(
sync_to_async(cached_dicts.set_up_cache_dicts)()
)
background_tasks.add(task)
task.add_done_callback(background_tasks.discard)
Очевидно, что это ужасный взлом, но он сработал в аналогичном случае использования.