我基本上希望能够创建一个由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
的方法的建议。
我感谢你的时间。谢谢。
答案 0 :(得分:1)
我的chord
由group
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文件组合以及它们中存在的代码的几种组合。我尝试了chords
,groups
,chains
,从不同的任务启动任务,组合任务。
一些组合最终确实有效,但我必须直接在.get()
上的wrtie_the_csv
任务中调用data
,但芹菜在4.0调用get中抛出warning
任务中的()会引发错误,所以我认为我不应该这样做..
从本质上讲,我的问题是(现在仍然是)任务设计不佳以及它们之间的流程。这让我想到了从其他任务中同步任务的问题。
我在我的问题中提出的while循环是当另一个任务状态变为COMPLETE
时尝试异步启动任务,然后在该任务完成后启动另一个任务等等......而不是同步放置芹菜是通过致电chord
或chain
来实现的。我似乎发现的(我不确定我对此是否正确)是因为在芹菜任务中你无法访问识别这些东西所需的范围。以下是来自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()