Django芹菜任务:新创建的模型DoesNotExist



为什么我创建了一个模型实例,当从芹菜任务直接开始查询后,没有找到?例如:

# 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()调用后的任何时候查询模型应该存在于数据库中。

Update 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()方法被调用时立即执行。

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

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

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

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

最新更新