与Celery的Django - 找不到现有的对象

时间:2015-08-26 09:35:25

标签: python django asynchronous celery

我在从另一个芹菜任务执行芹菜任务时遇到问题。

这是有问题的片段(数据对象已经存在于数据库中,其属性只是在finalize_data函数中更新):

def finalize_data(data):
    data = update_statistics(data)
    data.save()
    from apps.datas.tasks import optimize_data
    optimize_data.delay(data.pk)

@shared_task
def optimize_data(data_pk):
    data = Data.objects.get(pk=data_pk)
    #Do something with data

在optimize_data函数中调用失败,并且“数据匹配查询不存在。”

如果我在finalize_data函数中调用pk函数检索它可以正常工作。如果我将celery任务调用延迟一段时间,它也可以正常工作。

这一行:

optimize_data.apply_async((data.pk,), countdown=10)

而不是

optimize_data.delay(data.pk)

工作正常。但我不想在我的代码中使用hacks。是否有可能.save()调用异步阻止对该行/对象的访问?

3 个答案:

答案 0 :(得分:4)

我猜测你的调用者是在芹菜开始处理任务之前没有提交的事务中。因此,芹菜无法找到记录。这就是为什么添加倒计时使它工作。

1秒倒计时可能与您示例中的10秒倒计时一样有效。我在整个代码中使用了1秒倒计时来处理这个问题。

另一种解决方案是停止使用交易。

答案 1 :(得分:3)

我知道这是一个很老的帖子,但我今天偶然发现了这个问题。李的回答向我指出了正确的方向,但我认为今天存在更好的解决方案。

使用Django提供的on_commit处理程序可以解决这个问题,而不会在代码中使用一种可能不太直观的错误的计数倒计时方法。

我不确定问题发布时是否存在,但我只是发布答案,以便将来来这里的人知道替代方案。

答案 2 :(得分:1)

您可以使用on_commit挂钩来确保直到事务提交后才触发celery任务?

DjangoDocs#performing-actions-after-commit

这是Django 1.9中添加的功能。

from django.db import transaction

def do_something():
    pass  # send a mail, invalidate a cache, fire off a Celery task, etc.

transaction.on_commit(do_something)

您还可以将函数包装在lambda中:

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

您传递的函数将在成功调用on_commit()的假设数据库写入之后立即被调用。

如果在没有活动交易的情况下调用on_commit(),则回调将立即执行。

如果假设的数据库写操作被回滚(通常是在atomic()块中引发未处理的异常时),则函数将被丢弃并且从不调用。