在Celery中如何更新主要任务的状态,直到完成所有子任务?

时间:2012-04-06 16:47:36

标签: python django celery

在Celery中,我正在运行一个主要任务,为查询中的每个项目运行一个子任务。子任务应该并行运行。在UI上,我有一个进度条,显示总计完成了多少子任务。我正在更新主要任务状态以将信息提供给进度条。我的问题是主要任务在将所有子任务推送到代理后立即结束,因此我不能再更新他的状态。我希望主要任务可以等到所有子任务完成。可能吗?还有其他方法吗?这是我的伪代码(真正的代码不使用全局; - ))。

total = 0
done = 0

@task(ignore_result=True)
def copy_media(path):
    global total, done
    copy_media.update_state(state=STARTED, meta={'total': total, 'done': done})
    documents = Document.objects.all()
    total = documents.count()
    copy_media.update_state(state=STARTED, meta={'total': total, 'done': done})
    for document in documents:
        process_doc.delay(document, path, copy_media)

@task(ignore_result=True)
def process_doc(document, path, copy_media):
    global total, done
    # Do some stuff
    done += 1
    copy_media.update_state(state=STARTED, meta={'total': total, 'done': done})

3 个答案:

答案 0 :(得分:0)

我找到了使用TaskSet的方法。但我并不完全满意,因为我无法忽略子任务的结果。如果我忽略process_doc任务的结果results.ready()总是返回Falseresults.completed_count()总是返回0,等等。这是代码:

@task(ignore_result=True)
def copy_media(path):
    copy_media.update_state(state=STARTED, meta={'total': total, 'done': done})
    documents = Document.objects.all()
    total = documents.count()
    copy_media.update_state(state=STARTED, meta={'total': total, 'done': done})
    job = TaskSet(tasks=[process_doc.subtask((document, path))
                         for document in documents])
    results = job.apply_async()
    doc_name = ''
    while not results.ready():
        done = results.completed_count()
        if done:
            last = done - 1
            for idx in xrange(last, -1, -1):
                if results[idx].ready():
                    doc_name = results[idx].result
                    break
        copy_media.update_state(state=STARTED, meta={'total': total, 'done': done, 'doc-name': doc_name})
        time.sleep(0.25)

@task()
def process_doc(document, path):
    # Do some stuff
    return document

答案 1 :(得分:0)

您可以使用memcached支持的缓存来存储完整任务的数量。在django缓存API中甚至有cache.inrc用于原子增量,以确保并发计数更新不会搞砸。

此外,在所有子任务完成之前保持主要任务运行是个坏主意,因为你基本上阻止了一个芹菜工人很长一段时间。如果使用一个工作进程运行celery,这将导致永无止境的锁定。

答案 2 :(得分:-1)

我不知道您正在运行哪种版本的芹菜,但您可以查看Group子任务(3.0中的新增功能)。