Django post_save信号和celery任务之间可能存在的竞争状况

时间:2018-11-27 15:56:14

标签: django django-models celery celery-task

在django 2.0应用程序中,我有一个名为Document的模型,该模型可以将图像上传并保存到文件系统中。那部分起作用。我正在芹菜(v 4.2.1)任务中使用https://github.com/ageitgey/face_recognition对图像执行一些面部识别。我将图像的document_id传递给celery任务,以便面部识别任务可以找到要处理的图像。保存图像后,如果我从DocumentAdmin操作中手动调用face_recognition任务,则所有这些操作都很好。

我尝试通过models.py中的(models.signals.post_save, sender=Document)方法调用face_recognition任务,但在芹菜任务的这一行中,我的这一行出现了face_recognition错误:

document = Document.objects.get(document_id=document_id)

,错误是:

[2018-11-26 16:54:28,594: ERROR/ForkPoolWorker-1] Task biometric_identification.tasks.find_faces_task[428ca39b-aefb-4174-9906-ff2146fd6f14] raised unexpected: DoesNotExist('Document matching query does not exist.',)
Traceback (most recent call last):
  File "/home/mark/.virtualenvs/memorabilia-JSON/lib/python3.6/site-packages/celery/app/trace.py", line 382, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/home/mark/.virtualenvs/memorabilia-JSON/lib/python3.6/site-packages/celery/app/trace.py", line 641, in __protected_call__
    return self.run(*args, **kwargs)
  File "/home/mark/python-projects/memorabilia-JSON/biometric_identification/tasks.py", line 42, in find_faces_task
    document = Document.objects.get(document_id=document_id)
  File "/home/mark/.virtualenvs/memorabilia-JSON/lib/python3.6/site-packages/django/db/models/manager.py", line 82, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/home/mark/.virtualenvs/memorabilia-JSON/lib/python3.6/site-packages/django/db/models/query.py", line 403, in get
    self.model._meta.object_name
memorabilia.models.DoesNotExist: Document matching query does not exist.

此外,此错误不会一直发生,只会偶尔发生。在其余时间,该过程将继续进行;即保存图像并识别面部。

我在DocumentAdmin类中重写了save_model,但这只是将图像的一些元数据保存在另一个模型中。最后一行是对super().save_model(request, obj, form, change)的调用,因此我假设在那之后调用了post_save信号。

在我看来,在将模型保存到数据库与为数据库查询新创建的document_id的芹菜任务之间存在竞争。我以为保存模型后才会激活post_save信号?

为了解决这种可能的比赛状况,我是否必须在芹菜任务face_recognition中添加一些人为延迟,还是我错过了其他东西?

谢谢!

标记

2 个答案:

答案 0 :(得分:2)

检查保存Document模型的功能。它包装在atomic块中的某个位置,或者您已将ATOMIC_REQUESTS设置为True。因此,在调用post_save时,事务尚未提交。因此,您的模型当时并没有真正保存到数据库中。

答案 1 :(得分:0)

似乎信号有时会超过您的分贝写入速度!作为有害的解决方法,您可以做的是稍后再执行芹菜任务,只需几秒钟。

这是完成的方式:

your_task.apply_async(
            [document_id],
            countdown=5 # this is the delay in seconds - you can adapt it accordingly
        )

让我知道这是否适合您的情况!