芹菜任务PENDING

时间:2014-08-08 14:06:28

标签: python multiprocessing celery python-multithreading celery-task

我基本上希望能够创建一个由chord group组成的chains。除了我似乎无法完成这项工作的事实之外,所有子链都必须在和弦回调被触发之前完成。

所以我的想法是创建一个while循环,如:

data = [foo.delay(i) for i in bar]
complete = {}
L = len(data)
cnt = 0
while cnt != L:
    for i in data:
        ID = i.task_id
        try:
            complete[ID]
        except KeyError:
            if i.status == 'SUCCESS':
                complete[ID] = run_hourly.delay(i.result)
                cnt += 1
                if cnt >= L:
                    return complete.values()

因此,当任务准备就绪时,无需等待其他任务完成即可采取行动。

我遇到的问题是某些任务的状态永远不会超过'PENDING'状态。

如果我向SUCCESS'添加time.sleep(x)行,但for loop中有大量sub tasks,则所有任务都将达到data州该解决方案变得非常低效。

我使用memcached作为我的结果后端和rabbitmq。我的猜测是,循环遍历data并调用其任务属性的for循环的速度会产生竞争条件,从而打破与芹菜消息的连接,这使得这些僵尸任务保持不变处于'PENDING'状态。但话又说回来我可能完全错了,这肯定不会是第一次......

我的问题

为什么time.sleep(foo)在迭代刚刚启动的任务列表时需要避免永久PENDING任务?

当芹菜任务执行循环时它是否阻塞?当我尝试关闭陷入无限循环的工作程序时,我无法这样做并且必须手动找到运行该工作程序的python进程并将其终止。如果我让工作人员最终运行python进程,它将开始消耗几个内存,以指数方式增长,似乎没有约束。

对此问题的任何见解将不胜感激。我也欢迎提出有关完全避免while loop的方法的建议。

我感谢你的时间。谢谢。

1 个答案:

答案 0 :(得分:1)

我的chordgroup chains组成,正在芹菜任务中构建和执行。如果您需要访问这些任务的结果,这将产生问题。下面是我想要做的事情,我最终做的事情,以及我认为我在过程中学到了什么,以及它可以帮助其他人的总结。

- common_tasks.py -

from cel_test.celery import app

@app.task(ignore_result=False)
def qry(sql, writing=False):
    import psycopg2
    conn = psycopg2.connect(dbname='space_test', user='foo', host='localhost')
    cur = conn.cursor()
    cur.execute(sql)
    if writing == True:
        cur.close()
        conn.commit()
        conn.close()
        return

    a = cur.fetchall()
    cur.close()
    conn.close()
    return a

- foo_tasks.py -

from __future__ import absolute_import

from celery import chain, chord, group
import celery
from cel_test.celery import app
from weather.parse_weather import parse_weather
from cel_test.common_tasks import qry
import cPickle as PKL
import csv
import requests


@app.task(ignore_results=False)
def write_the_csv(data, file_name, sql):
    with open(file_name, 'wb') as fp:
        a = csv.writer(fp, delimiter=',')
        for i in data:
            a.writerows(i)
    qry.delay(sql, True)
    return True

@app.task(ignore_result=False)
def idx_point_qry(DIR='/bar/foo/'):
    with open(''.join([DIR, 'thing.pkl']), 'rb') as f:
            a = PKL.load(f)
    return [(i, a[i]) for i in a]

@app.task(ignore_results=False)
def load_page(url):
    page = requests.get(url, **{'timeout': 30})
    if page.status_code == 200:
        return page.json()

@app.task(ignore_results=False)
def run_hourly(page, info):
    return parse_weather(page, info).hourly()

@app.task(ignore_results=False)
def pool_loop(info):
    data = []
    for iz in info:
        a = chain(load_page.s(url, iz), run_hourly.s())()
        data.append(a)
    return data



@app.task(ignore_results=False)
def run_update(file_name, sql, writing=True):
    chain(idx_point_qry.s(), pool_loop.s(file_name, sql), write_the_csv.s(writing, sql))()
    return True

--- separate.py文件---

from foo_tasks import *

def update_hourly_weather():
    fn = '/weather/csv_data/hourly_weather.csv'
    run_update.delay(fn, "SELECT * from hourly_weather();")
    return True

update_hourly_weather()

我尝试了上面列出的30个左右的.py文件组合以及它们中存在的代码的几种组合。我尝试了chordsgroupschains,从不同的任务启动任务,组合任务。

一些组合最终确实有效,但我必须直接在.get()上的wrtie_the_csv任务中调用data,但芹菜在4.0调用get中抛出warning任务中的()会引发错误,所以我认为我不应该这样做..

从本质上讲,我的问题是(现在仍然是)任务设计不佳以及它们之间的流程。这让我想到了从其他任务中同步任务的问题。

我在我的问题中提出的while循环是当另一个任务状态变为COMPLETE时尝试异步启动任务,然后在该任务完成后启动另一个任务等等......而不是同步放置芹菜是通过致电chordchain来实现的。我似乎发现的(我不确定我对此是否正确)是因为在芹菜任务中你无法访问识别这些东西所需的范围。以下是来自state portion in the celery documentation on tasks的引用“断言世界是任务的责任”。

我正在启动任务,任务根本不存在,因此无法了解它们。

我的解决方案是加载并遍历.pkl文件并同步启动一组chains并回调。我基本上用下面的代码替换pool_loop任务,并同步而不是异步地启动任务。

- the_end.py -

from foo_tasks import *
from common_tasks import *

def update_hourly_weather():
    fn = '/weather/csv_data/hourly_weather.csv'
    dd = []
    idx = idx_point_qry()
    for i in idx:
        dd.append(chain(load_page.s(i, run_hourly.s(i)))
    vv = chord(dd)(write_the_csv.s(fn, "SELECT * from hourly_weather();"))
    return

update_hourly_weather()