如何判断任务是否已在django芹菜中排队?

如何判断任务是否已在django芹菜中排队?,django,message-queue,celery,django-celery,Django,Message Queue,Celery,Django Celery,以下是我的设置: django 1.3 芹菜2.2.6 django芹菜2.2.4 djkombu 0.9.2 在我的settings.py文件中 BROKER_BACKEND = "djkombu.transport.DatabaseTransport" i、 我只是在用数据库把任务排成队列 现在谈谈我的问题:我有一个用户发起的任务,可能需要几分钟才能完成。我希望每个用户只运行一次任务,并将任务结果缓存在临时文件中,因此如果用户再次启动任务,我只返回缓存的文件。我的视图函数中有如下代码:

以下是我的设置:

  • django 1.3
  • 芹菜2.2.6
  • django芹菜2.2.4
  • djkombu 0.9.2
在我的settings.py文件中

BROKER_BACKEND = "djkombu.transport.DatabaseTransport"
i、 我只是在用数据库把任务排成队列

现在谈谈我的问题:我有一个用户发起的任务,可能需要几分钟才能完成。我希望每个用户只运行一次任务,并将任务结果缓存在临时文件中,因此如果用户再次启动任务,我只返回缓存的文件。我的视图函数中有如下代码:

task_id = "long-task-%d" % user_id
result = tasks.some_long_task.AsyncResult(task_id)

if result.state == celery.states.PENDING:
    # The next line makes a duplicate task if the user rapidly refreshes the page
    tasks.some_long_task.apply_async(task_id=task_id)
    return HttpResponse("Task started...")
elif result.state == celery.states.STARTED:
    return HttpResponse("Task is still running, please wait...")
elif result.state == celery.states.SUCCESS:
    if cached_file_still_exists():
        return get_cached_file()
    else:
        result.forget()
        tasks.some_long_task.apply_async(task_id=task_id)
        return HttpResponse("Task started...")
这段代码几乎可以工作。但是当用户快速重新加载页面时,我遇到了一个问题。从任务排队到最终将任务从队列中拉出并交给工作人员之间有1-3秒的延迟。在此期间,任务的状态保持挂起状态,这会导致视图逻辑启动重复任务


我需要的是某种方法来判断任务是否已经提交到队列中,这样我就不会再提交两次。在芹菜中有没有标准的方法

您可以通过将结果手动存储在数据库中来作弊。让我解释一下这会有什么帮助

例如,如果使用RDBMS(带列的表-任务id、状态、结果):

视图部分:

  • 使用事务管理
  • 使用“更新选择”获取任务id==“长任务-%d”%user\u id的行。更新选择将阻止其他请求,直到此请求提交或回滚
  • 如果它不存在-将状态设置为挂起并启动“some_long_任务”,结束请求
  • 如果状态为挂起-通知用户
  • 如果状态为SUCCESS-将状态设置为PENDING,启动任务,返回“result”列指向的文件。我的假设是,您希望在得到结果后重新运行任务。承诺
  • 如果状态为错误-将状态设置为挂起,启动任务,通知用户。承诺
  • 任务部分:

  • 准备文件,放入try,catch块
  • 成功时-使用state=success,result更新正确的行
  • 失败时-使用state=ERROR更新正确的行

  • 我和Redis一起解决了这个问题。只需在redis中为每个任务设置一个键,然后在任务的after_return方法中从redis中删除该键。Redis是轻量级和快速的。

    我不认为(正如Tomek和其他人所建议的那样)使用数据库是实现这种锁定的方法。django有内置的缓存框架,该框架应足以完成此锁定,并且必须更快。见:


    Django可以配置为使用
    memcached
    作为其缓存后端,这可以分布在多台机器上。。。我觉得这样更好。想法?

    能否
    再次启动长任务()?如果是这样的话,这可能是一个足够的延迟,可以防止用户和芹菜之间的竞争情况。再次启动长任务()不会导致重复任务。我更新了我的示例,以显示代码将在何处执行重复任务。这不是我的问题。
    可以再次启动长任务吗()
    检查并等待任务在完成之前是否已移出挂起状态?当然可以,但这似乎无法完成任何事情。forget()删除结果并将任务放回挂起状态,因此我们已经“知道”状态,除非出现另一个不太可能的争用条件。在考虑较小的边缘情况之前,我想先解决我的原始问题。如果无法看到挂起状态(因为您一直等到它通过),那么您的问题就解决了,对吗?还是有别的事情发生了?一个很好的解决方案,正是我想要的。谢谢你的链接!