【发布时间】:2013-06-07 18:51:32
【问题描述】:
问题
我已将长时间运行的任务分割成逻辑子任务,因此我可以在每个子任务完成时报告其结果。但是,我正在尝试报告一项实际上永远不会完成的任务的结果(而是在执行过程中产生值),并且我正在努力使用我现有的解决方案来做到这一点。
背景
我正在为我编写的一些 Python 程序构建一个 Web 界面。用户可以通过网络表单提交作业,然后回来查看作业的进度。
假设我有两个函数,每个函数都通过单独的表单访问:
-
med_func:执行大约需要 1 分钟,结果将传递给render(),这会产生额外的数据。 -
long_func:返回一个生成器。每个yield大约需要 30 分钟,并且应该报告给用户。有这么多产量,我们可以认为这个迭代器是无限的(仅在revoked 时终止)。
代码,当前实现
使用med_func,我报告结果如下:
在提交表单时,我将AsyncResult 保存到Django session:
task_result = med_func.apply_async([form], link=render.s())
request.session["task_result"] = task_result
结果页面的 Django 视图访问此AsyncResult。任务完成后,结果将保存到一个对象中,该对象作为上下文传递给 Django 模板。
def results(request):
""" Serve (possibly incomplete) results of a session's latest run. """
session = request.session
try: # Load most recent task
task_result = session["task_result"]
except KeyError: # Already cleared, or doesn't exist
if "results" not in session:
session["status"] = "No job submitted"
else: # Extract data from Asynchronous Tasks
session["status"] = task_result.status
if task_result.ready():
session["results"] = task_result.get()
render_task = task_result.children[0]
# Decorate with rendering results
session["render_status"] = render_task.status
if render_task.ready():
session["results"].render_output = render_task.get()
del(request.session["task_result"]) # Don't need any more
return render_to_response('results.html', request.session)
此解决方案仅在函数实际终止时有效。我无法将long_func 的逻辑子任务链接在一起,因为yields 的数量未知(long_func 的循环的每次迭代可能不会产生结果)。
问题
有没有什么明智的方法可以从一个极其长时间运行的 Celery 任务中访问产生的对象,以便在生成器耗尽之前显示它们?
【问题讨论】:
-
这个问题含糊不清,cmets 提出了完全不同的问题。
-
您能否详细说明实际问题“是否有任何明智的方法可以从极其长时间运行的 Celery 任务中渲染产生的对象?”?使用“渲染”,您的意思是您希望以某种方式能够在视图函数中获得未结束任务的结果?这些结果看起来如何(模型实例?)?
-
公平点,@Brent 和 @Bernhard;我在这里要做的实际上并不是渲染结果本身,而是能够在生成器完成之前访问产生的值(以便它们可以在页面上呈现)。所以,是的,我本质上是在任务终止之前,在视图函数中尽可能多地显示任务的进度。
-
和@Bernhard,“结果”只是标准的 Python 对象,完全独立于 Celery 和 Django(我可以将该程序用作独立的 Python 应用程序)。