celery 检查返回状态( result.ready)时,会出现死循环

2017-05-17 13:39:44 +08:00
 akmonde

RT:小弟这边为了保证某 task 优先运行完成,采用了检查结果返回状态的法子:

while not result.ready():

比如下面的样例代码,任务没有 ready 就一直循环( PS:用 result.get 也会出现类似的情况):

from tasks import add
result = add.delay(4, 4) #不要直接 add(4, 4),这里需要用 celery 提供的接口 delay 进行调用
while not result.ready():
    time.sleep(1)
print 'task done: {0}'.format(result.get())

结果小弟发现那个需要优先运行的任务,就一直处在 received 的状态,result.ready()的返回一直是 False。 此前以为 task 函数的原因,检查了并没有发现问题。

很急,在线求大神解答为啥会出现这种情况。 感谢!

6421 次点击
所在节点    Python
20 条回复
NaVient
2017-05-17 15:39:51 +08:00
while True:
NaVient
2017-05-17 15:40:49 +08:00
while True:
if result.ready():
break


这样才是循环,你那个一开始任务是 false,循环都进不去
akmonde
2017-05-17 16:22:49 +08:00
@NaVient
result.ready()结果开始就是 False 啊,循环是进去了的,time.sleep(1)会一直下去,这个我试过打印内容印证过的。
但我要做的那个任务始终在 PENDING,或者说是 RECEIVED 状态,并没有开始做,不用循环,直接 result.ready()是可以运行那个任务的,但是却没有锁住的效果了。
r0okit
2017-05-17 17:53:56 +08:00
这段代码就是例子代码,没问题,请教别人的时候给出详细的信息,用的是 redis 还是 rabbitmq,配置贴上來
akmonde
2017-05-17 20:31:17 +08:00
@r0okit
首先感谢这位朋友,贴下 redis 的配置如下:
celery = Celery('achrief', backend='redis://localhost:6379/0', broker='redis://localhost:6379/0')
我这边仔细比较过,真实代码跟样例情况是一模一样的,换了变量和函数名而已,这里就不贴了。
另外,celery 配置文件里添加了以下内容,不过并没有起作用:
CELERY_IGNORE_RESULT=False
另外,我这边是 Linux 环境,有朋友说的 win 下运行可以加-p threads 或者啥 pool 参数的我也试过了,没有起作用。
zsz
2017-05-17 20:43:40 +08:00
celery server 运行起来了么?
akmonde
2017-05-17 21:04:21 +08:00
@zsz 程序一直是正常运行的,只不过最近加了检查返回状态才这样,因此应该不是 celery server 的锅。
akmonde
2017-05-18 07:55:44 +08:00
@r0okit
我那边单独测了上面提到的 demo 代码,是可用的。
但我这边是同时运行了多个任务,其中夹杂了这个优先级高的任务,就会出问题了,代码如下:
if item in match_items:
result = eval(item).delay(x,y)
result_list.append(eval_result)
else:
eval(item).delay(x,y)
for result_item in result_list:
while not result_item.ready():
time.sleep(2)
然后那个任务会一直在 PENDING,或者说是 RECEIVED 状态,并没有启动,一直 sleep。
zsz
2017-05-18 08:06:45 +08:00
其他任务都不是 delay 执行的吧?
akmonde
2017-05-18 12:33:37 +08:00
@zsz 也是 delay 执行的,8 楼给出了那部分的代码,兄弟麻烦给看看。
r0okit
2017-05-18 13:13:41 +08:00
@akmonde 你好,8 楼的代码贴的再完整点,解释下 eval 用在这里的意图,还有这段代码不是放到任务里面的吧,感觉问题就在这块了
pkking
2017-05-18 20:01:41 +08:00
你这个逻辑是不是应该用 chain 或者 callback ?
akmonde
2017-05-18 20:33:11 +08:00
@r0okit eval 是为了把前端传过来的字符串,作为函数名执行哈,咱们可以把它这样等价:
eval(item).delay(x,y) == add.delay(x,y)
另外,确实这段代码是放在一个任务函数里去调用的,用不用 delay 都出现了这种情况。
akmonde
2017-05-18 20:34:34 +08:00
@pkking 感谢回复,不过小弟学识有限,没有理解您的意思,您能稍微举个例子么?
zsz
2017-05-18 20:52:38 +08:00
@akmonde
加我们的群问效率高些,一群工程师组建的面向初学者的
Python Linux 学习群,qq 群号:278529278,
Php Linux 学习群,qq 群号:476648701,
非商业性质,拒绝广告,只接收真正想学这方面技术的朋友,交流学习,申请请说明来自 v2ex
r0okit
2017-05-19 12:56:12 +08:00
@akmonde @pkking 他说的没错,你这个逻辑不对,最好是改用 chain,而不是在一个任务里面调用另一个任务,官网中有对这个的介绍,还有你可以用个字典名字映射函数,不要用 eval,外部传入的都不可信
akmonde
2017-05-19 13:38:38 +08:00
@r0okit eval 之前已经对能执行恶意命令的特殊字符进行了过滤,也不涉及库查询,所以应该不会有安全方面的问题。
我去研究下 chain 和怎么用字典名字映射函数,先谢谢您。
这问题也是够折腾的,这两天在一步步替换正常的配置和代码进行对比,真是头疼,问题出现的有点隐蔽。
r0okit
2017-05-19 15:16:48 +08:00
@akmonde 我再啰嗦下,eval 你是防不住的,相信我,只要你放到生产环境上,各种猥琐的注入方法会让你大开眼界
akmonde
2017-05-20 08:10:01 +08:00
@r0okit @pkking 非常感谢大牛们的指导,确实黑名单难以过滤完全特殊字符。另外我似乎查出问题所在了,确实是 result.ready()是放在 delay()任务中执行,那里就会阻塞运行不下去了。
我这边前端采用了 flower 的接口控制任务的启动,话说 flower 有参数可以不调用 delay 么?
另外,我试了下如果不调用 delay 的话,不使用 chain 也是可以用的。
是否 flower 前端传过来的参数是必须调用 delay,然后必须用 chain 或者 signature 之类的才能破?
akmonde
2017-05-22 15:22:42 +08:00
@r0okit @pkking
两位大牛,不好意思再次打扰一下。
我这边看了下,我前端 flower 通过参数传过来,进行程序启动的那个函数,肯定是需要 delay 的,调用方式就下面两种:
http://flower-docs-cn.readthedocs.io/zh/latest/api.html#post-api-task-async-apply
http://flower-docs-cn.readthedocs.io/zh/latest/api.html#post-api-task-send-task
那么问题来了,我看了下案例:
http://celery.readthedocs.io/en/latest/userguide/tasks.html#avoid-launching-synchronous-subtasks
这里调用 chain 是不能使用 delay 的函数的,好像是需要在一个普通函数或者在程序主体里去调用 chain 的。
那么在程序入口需要在 delay 的函数里的情况下,我应该如何去使用 chain 呢?这好像是个悖论,没想明白应该怎么弄。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/361935

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX