#python #django #celery #django-orm #gevent
Вопрос:
Мы используем задания сельдерея наряду с Django, и в рамках различных задач сельдерея есть несколько случаев, когда задача сельдерея заключается в чтении и записи в базу данных через ORM Django.
Время от времени при использовании ORM внутри задачи сельдерея задачи бросают:
Synchronousonlyоперация: Вы не можете вызвать это из асинхронного контекста — используйте поток или sync_to_async.
Мне кажется странным, что это происходит иногда, а не каждый раз, когда запрос делается через ORM? Во-вторых, при попытке решить эту проблему в соответствии с предложениями в документации Django здесь:
https://docs.djangoproject.com/en/3.2/topics/async/
вот так: Пример использования sync_to_asynch
Я сталкиваюсь с другой проблемой: ошибка типа: объект «сопрограмма» не может быть повторен
Мои вопросы таковы:
- Почему эта проблема возникает только время от времени, а не каждый раз, когда я выполняю запрос с помощью ORM внутри задачи сельдерей?
- Есть ли способ решить эту проблему?
Окружающая среда
Задачи сельдерея выполняются с помощью gevent следующим образом: сельдерей -Работник задач-P gevent -c 10 -l ИНФОРМАЦИЯ -E
Python 3.8
Джанго 3.1.4
Сельдерей 5.1.0
Комментарии:
1. Убедитесь, что вы не передаете объекты, такие как модели, через аргументы, если вам нужно передать данные, связанные с базой данных, просто передайте
pk
, а затем в функции выполните запрос, потому что сельдерей не работает нормально с объектами ORM, переданными в качестве параметров.2. Спасибо! Однако с этим уже разобрались, и в данном случае это не проблема.
3. Пожалуйста, укажите соответствующий код непосредственно в своем вопросе, а также полную обратную связь.
Ответ №1:
sync_to_async()
вернет сопрограмму. Как указывает ошибка типа, вы не можете выполнять итерацию сопрограммы напрямую. Вы должны await
это сделать, как показано в примере.
Из документов:
from asgiref.sync import sync_to_async
results = await sync_to_async(Blog.objects.get, thread_sensitive=True)(pk=123)
На вашей фотографии вы не await
звоните.
Комментарии:
1. Спасибо! Это абсолютно верно. Следующая проблема, с которой я сталкиваюсь, если жду вызова, заключается в том, что для этого требуется, чтобы объявление функции было асинхронным. Проблема, которую я думаю, заключается в том, что Celery gevent порождает зеленые потоки (поскольку я использую gevent), и на самом деле это не асинхронный контекст, который можно объявить с помощью ключевого слова async, поскольку сельдерей заботится об этом асинхронном порождении зеленого потока. Есть ли какой-либо способ обойти это, или мне нужно прибегнуть к использованию prefork, а не gevent в настройках сельдерея?