在 Celery 任务中保存对象后,Django 匹配查询不存在

and*_*rei 6 python mysql django celery django-celery

我有以下代码:

@task()
def handle_upload(title, temp_file, user_id):
    .
    .
    .
    photo.save()
    #if i insert here "photo2 = Photo.objects.get(pk=photo.pk)" it works, including the         view function
    return photo.pk

#view function
def upload_status(request):
    task_id = request.POST['task_id']

    async_result = AsyncResult(task_id)
    photo_id = async_result.get()
    if async_result.successful(): 
        photo = Photo.objects.get(pk=photo_id)
Run Code Online (Sandbox Code Playgroud)

我使用 ajax 请求来检查上传的文件,但在 celery 任务完成后,我得到一个照片匹配查询不存在。照片 pk 确实存在并被退回。如果我手动查询数据库,它就可以工作。这是某种数据库延迟吗?我该如何解决?我正在使用 Django 1.4 和 Celery 3.0

ast*_*vic 2

您可以通过在 django 视图中添加延迟以在任务成功完成后等待几秒钟来确认这是否是滞后问题。如果这解决了问题,您可能需要将 handle_upload 包装在事务中以进行阻止,直到数据库完全确认其已完成后再返回。

除了 Django 之外,DB 也有自己的缓存。当 django 调用查询集时,它会从自己的缓存中获取过时的数据(不太可能,除非您重用查询集,我在您发布的代码部分中没有看到),或者数据库正在缓存同一 Django 连接的结果。

例如,如果您要在全新的 django 请求/视图中完成 celery 任务后调用后处理,您可能会很好地看到数据库中的新更改。但是,由于您的视图在任务执行时被阻止(顺便说一句,这违背了 celery 的目的),django 内部仅保留进入视图时数据库的快照。因此,您的 get 失败,并且您在进入 django shell 时直接确认了此行为。

您可以通过以下任一方法解决此问题,就像您已经做的那样:

  • 调用事务管理来刷新快照
  • 更改数据库端点缓存和自动提交策略
  • 让 celery 在完成处理后回调 django (网络请求)(这可能是您想要做的,因为阻止 django 达不到目的)