在 celery 任务中查询 Django ORM:SynchronousOnlyOperation:您不能从异步上下文中调用它 - 使用线程或 sync_to_async
Posted
技术标签:
【中文标题】在 celery 任务中查询 Django ORM:SynchronousOnlyOperation:您不能从异步上下文中调用它 - 使用线程或 sync_to_async【英文标题】:Querying Django ORM inside celery task: SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async 【发布时间】:2021-12-23 03:55:19 【问题描述】:我们在 Django 旁边使用 celery 作业,在不同的 celery 任务中,有好几次 celery 任务通过 Django 的 ORM 读取和写入数据库。
每隔一段时间在 celery 任务中使用 ORM 时,任务会抛出:
SynchronousOnlyOperation:您不能从异步上下文中调用它 - 使用线程或 sync_to_async。
我觉得奇怪的是它有时会发生,而不是每次通过 ORM 进行查询时?其次,当尝试按照此处 Django 文档中的建议解决它时:
https://docs.djangoproject.com/en/3.2/topics/async/
像这样:Example of sync_to_asynch ussage
我遇到了另一个问题: TypeError: 'coroutine' object is not iterable
我的问题是:
为什么这个问题只是偶尔出现,而不是每次我在 celery 任务中使用 ORM 查询时都会出现?
有办法解决吗?
环境
celery 任务使用 gevent 运行,如下所示: celery -A 任务工作者 -P gevent -c 10 -l INFO -E
Python 3.8
Django 3.1.4
芹菜 5.1.0
【问题讨论】:
如果您需要传递与数据库相关的数据,请确保不要通过 args 传递模型等对象,只需传递pk
然后在函数中进行查询,因为 celery 没有使用作为参数传递的 ORM 对象可以正常工作。
谢谢!不过,这已经处理过了,在这种情况下不是问题。
请在您的问题中直接包含相关代码以及完整的回溯。
【参考方案1】:
sync_to_async()
将返回一个协程。正如 TypeError 所暗示的,您不能直接迭代协程。你必须await
它,如示例所示。
来自文档:
from asgiref.sync import sync_to_async
results = await sync_to_async(Blog.objects.get, thread_sensitive=True)(pk=123)
在你的图片中,你没有await
这个电话。
【讨论】:
谢谢!这是完全正确的。如果我等待调用,我遇到的下一个问题是它要求函数声明是异步的。我认为当时的问题是 Celery gevent 正在产生绿色线程(因为我使用 gevent),它并不是一个可以用 async 关键字声明的异步上下文,因为 celery 正在处理这个线程异步绿色线程的产生。有什么办法可以解决这个问题,还是我必须在我的 celery 设置中使用 prefork 而不是 gevent?以上是关于在 celery 任务中查询 Django ORM:SynchronousOnlyOperation:您不能从异步上下文中调用它 - 使用线程或 sync_to_async的主要内容,如果未能解决你的问题,请参考以下文章
如何在 celery 任务中强制 django-orm 中的单个保存的 db 提交
在 Django Admin 中保存新对象并发送到 Celery 任务后,匹配查询不存在
Django celery 任务:新创建的模型 DoesNotExist