Django celery 任务:新创建的模型 DoesNotExist

Posted

技术标签:

【中文标题】Django celery 任务:新创建的模型 DoesNotExist【英文标题】:Django celery task: Newly created model DoesNotExist 【发布时间】:2013-03-25 07:09:06 【问题描述】:

为什么我创建的模型实例在之后直接启动的芹菜任务中查询时找不到?例如:

# app.views

model = Model.objects.create()    # I create my lovely model in a view
from app.tasks import ModelTask   # I import my Async celery task
ModelTask.delay(model.pk)         # I start the task

这一切看起来都很好,如果我在create() 调用之后的任何时候查询该模型应该存在于数据库中。

更新 1:在我看来,我正在使用 Django 提供的默认 transaction.autocommit 行为。

但是下面的任务会抛出一个ObjectDoesNotExist 异常:

# app.tasks

class ModelTask(Task):
    def run(self, model_pk):
        from app.models import Model
        Model.objects.get(pk=model_pk)

在我的测试中,正如预期的那样,model_pk 是一个正确的正整数 ID。

结论

我假设这里出现了一些异步/“独立进程”问题,但我不知道它是什么。如果觉得我犯了一些明显的错误。

我不认为数据库事务是答案,因为 Django 的默认“自动提交”方法可确保在调用 create() 方法后立即执行数据库操作。

【问题讨论】:

你检查过它确实保存到数据库吗?并且 pk 值与返回的值相同吗?您是否在日志文件中查看过警告或错误? 该模型之后直接在 Django admin 中可见。而且虽然我没有具体检查过,但PK看起来在正确的范围内。我忘了提到有时会找到模型,这就是为什么我认为这是一个种族问题。 你能给model的代码吗(尽可能简化,同时仍然复制错误)?特别是,我假设:pk = models.AutoField(primary_key=True)? 【参考方案1】:

这些答案需要更新。 Django 现在有 transaction.on_commit() 专为这个确切的问题而构建,他们甚至提供了一个带有任务的示例:

transaction.on_commit(lambda: some_celery_task.delay('arg1'))

https://docs.djangoproject.com/en/2.1/topics/db/transactions/#django.db.transaction.on_commit

【讨论】:

【参考方案2】:

我的代码中遇到了同样的问题。经过长时间的调查,我发现因为我使用了@transaction.commit_on_success 装饰器,所以出现了竞态条件。所以事务只有在视图返回后才提交。这是在我调用 celery 任务之后发生的。

一旦我删除了“commit_on_success”装饰器,一切都开始按预期工作。因为Django的default transaction behavior是在任何数据库修改操作后提交事务。

您可能还想确保您没有使用 TransactionMiddleware,因为它与 @transaction.commit_on_success 装饰器做类似的事情。如果你想继续使用它,你应该考虑在你的视图中使用 @transaction.autocommit 装饰器和 celery 任务,或者 @transaction.commit_manually。

【讨论】:

我正在使用默认事务管理(自动提交),这就是它如此奇怪的原因。我已经添加了transaction.commit(),尽管它不应该有任何效果,但它似乎可以防止错误。可能是因为它延迟了几个滴答声。 @MarcusWhybrow 那么您的视图可能实际上驻留在transaction.commit_on_success 中,您能否检查一下,例如在Django 1.5 和更早版本下调用transaction.is_managed() ?例如,Django Admin 中的add_view 周围有commit_on_success。因此,如果由add_view 触发的post_save 信号调用,则您的代码在托管事务中。.. @okm 不知道transaction.is_managed() 检查。听起来很有用。免责声明:我处理这个问题已经有几个月了,所以我会牢记在心。

以上是关于Django celery 任务:新创建的模型 DoesNotExist的主要内容,如果未能解决你的问题,请参考以下文章

Django ElasticSearch Celery 任务模型调用返回“str”对象不可调用

如何在任务中获取芹菜结果模型(使用 django-celery-results)

Celery 在远程任务上使用 Django Result Backend

Django 模型和 Celery 周期性任务

为啥当我尝试在 celery 任务中使用模型时,django 会引发“应用程序尚未加载”错误?

重试丢失或失败的任务(Celery、Django 和 RabbitMQ)