简体   繁体   English

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

[英]Django with Celery - existing object not found

I am having problem with executing celery task from another celery task.我在从另一个 celery 任务执行 celery 任务时遇到问题。

Here is the problematic snippet (data object already exists in database, its attributes are just updated inside finalize_data function):这是有问题的片段(数据对象已经存在于数据库中,它的属性只是在 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

Get call in optimize_data function fails with "Data matching query does not exist."调用 optimize_data 函数失败,并显示“数据匹配查询不存在”。

If I call the retrieve by pk function in finalize_data function it works fine.如果我在 finalize_data 函数中调用 pk 函数检索它工作正常。 It also works fine if I delay the celery task call for some time.如果我将 celery 任务调用延迟一段时间,它也可以正常工作。

This line:这一行:

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

instead of代替

optimize_data.delay(data.pk)

works fine.工作正常。 But I don't want to use hacks in my code.但我不想在我的代码中使用 hacks。 Is it possible that .save() call is asynchronously blocking access to that row/object? .save() 调用是否有可能异步阻止对该行/对象的访问?

I know that this is an old post but I stumbled on this problem today.我知道这是一个旧帖子,但我今天偶然发现了这个问题。 Lee's answer pointed me to the correct direction but I think a better solution exists today. Lee 的回答为我指明了正确的方向,但我认为今天存在更好的解决方案。

Using the on_commit handler provided by Django this problem can be solved without a hackish way of countdowns in the code which might not be intuitive to the user about why it exsits.使用 Django 提供的on_commit处理程序可以解决这个问题,而无需在代码中采用on_commit式的倒计时方式,这对于用户来说可能不直观它为什么存在。

I'm not sure if this existed when the question was posted but I'm just posting the answer so that people who come here in the future know about the alternative.我不确定在发布问题时这是否存在,但我只是发布答案,以便将来来到这里的人知道替代方案。

I'm guessing your caller is inside a transaction that hasn't committed before celery starts to process the task.我猜你的调用者在芹菜开始处理任务之前没有提交的事务中。 Hence celery can't find the record.因此芹菜找不到记录。 That is why adding a countdown makes it work.这就是为什么添加倒计时使其起作用的原因。

A 1 second countdown will probably work as well as the 10 second one in your example. 1 秒倒计时可能与示例中的 10 秒倒计时一样有效。 I've used 1 second countdowns throughout code to deal with this issue.我在整个代码中使用了 1 秒倒计时来处理这个问题。

Another solution is to stop using transactions.另一种解决方案是停止使用事务。

You could use an on_commit hook to make sure the celery task isn't triggered until after the transaction commits?您可以使用on_commit钩子来确保 celery 任务在事务提交之后才触发?

DjangoDocs#performing-actions-after-commit DjangoDocs#performing-actions-after-commit

It's a feature that was added in Django 1.9.这是 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)

You can also wrap your function in a lambda:您还可以将函数包装在 lambda 中:

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

The function you pass in will be called immediately after a hypothetical database write made where on_commit() is called would be successfully committed.您传入的函数将在调用 on_commit() 的假设数据库写入成功提交后立即调用。

If you call on_commit() while there isn't an active transaction, the callback will be executed immediately.如果在没有活动事务时调用 on_commit(),回调将立即执行。

If that hypothetical database write is instead rolled back (typically when an unhandled exception is raised in an atomic() block), your function will be discarded and never called.如果该假设的数据库写入被回滚(通常是在 atomic() 块中引发未处理的异常时),您的函数将被丢弃并且永远不会被调用。

I have come to complement the good response of @Vignesh 我来补充@Vignesh的良好反应

The example of the problem would be solved like this: 该问题的示例将通过以下方式解决:

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

Does anymore else think that is the rigth answer? 还有其他人认为这是正确的答案吗? Or are there other clearer and optimized responses? 还是还有其他更清晰,更优化的回应? Thanks 谢谢

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

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