17

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

# 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:我正在使用transaction.autocommitDjango 提供的默认行为,以供我查看。

但是下面的任务会引发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()调用该方法后立即执行数据库操作。

4

2 回答 2

12

这些答案需要更新。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

于 2019-02-21T14:41:35.077 回答
7

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

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

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

于 2013-04-12T04:34:20.573 回答