繁体   English   中英

带有芹菜的 Django - 找不到现有对象

[英]Django with Celery - existing object not found

我在从另一个 celery 任务执行 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() 调用是否有可能异步阻止对该行/对象的访问?

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

使用 Django 提供的on_commit处理程序可以解决这个问题,而无需在代码中采用on_commit式的倒计时方式,这对于用户来说可能不直观它为什么存在。

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

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

1 秒倒计时可能与示例中的 10 秒倒计时一样有效。 我在整个代码中使用了 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() 块中引发未处理的异常时),您的函数将被丢弃并且永远不会被调用。

我来补充@Vignesh的良好反应

该问题的示例将通过以下方式解决:

from django.db import transaction

def finalize_data(data):
    data = update_statistics(data)
    data.save()
    from apps.datas.tasks import optimize_data
    transaction.on_commit(lambda: optimize_data.delay(data.pk)) <---- Here

还有其他人认为这是正确的答案吗? 还是还有其他更清晰,更优化的回应? 谢谢

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM