V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
akmonde
V2EX  ›  Python

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

  •  
  •   akmonde · 2017-05-17 13:39:44 +08:00 · 6189 次点击
    这是一个创建于 2507 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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 函数的原因,检查了并没有发现问题。

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

    20 条回复    2017-05-22 15:22:42 +08:00
    NaVient
        1
    NaVient  
       2017-05-17 15:39:51 +08:00
    while True:
    NaVient
        2
    NaVient  
       2017-05-17 15:40:49 +08:00
    while True:
    if result.ready():
    break


    这样才是循环,你那个一开始任务是 false,循环都进不去
    akmonde
        3
    akmonde  
    OP
       2017-05-17 16:22:49 +08:00
    @NaVient
    result.ready()结果开始就是 False 啊,循环是进去了的,time.sleep(1)会一直下去,这个我试过打印内容印证过的。
    但我要做的那个任务始终在 PENDING,或者说是 RECEIVED 状态,并没有开始做,不用循环,直接 result.ready()是可以运行那个任务的,但是却没有锁住的效果了。
    r0okit
        4
    r0okit  
       2017-05-17 17:53:56 +08:00
    这段代码就是例子代码,没问题,请教别人的时候给出详细的信息,用的是 redis 还是 rabbitmq,配置贴上來
    akmonde
        5
    akmonde  
    OP
       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
        6
    zsz  
       2017-05-17 20:43:40 +08:00 via iPhone
    celery server 运行起来了么?
    akmonde
        7
    akmonde  
    OP
       2017-05-17 21:04:21 +08:00
    @zsz 程序一直是正常运行的,只不过最近加了检查返回状态才这样,因此应该不是 celery server 的锅。
    akmonde
        8
    akmonde  
    OP
       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
        9
    zsz  
       2017-05-18 08:06:45 +08:00 via iPhone
    其他任务都不是 delay 执行的吧?
    akmonde
        10
    akmonde  
    OP
       2017-05-18 12:33:37 +08:00
    @zsz 也是 delay 执行的,8 楼给出了那部分的代码,兄弟麻烦给看看。
    r0okit
        11
    r0okit  
       2017-05-18 13:13:41 +08:00
    @akmonde 你好,8 楼的代码贴的再完整点,解释下 eval 用在这里的意图,还有这段代码不是放到任务里面的吧,感觉问题就在这块了
    pkking
        12
    pkking  
       2017-05-18 20:01:41 +08:00
    你这个逻辑是不是应该用 chain 或者 callback ?
    akmonde
        13
    akmonde  
    OP
       2017-05-18 20:33:11 +08:00
    @r0okit eval 是为了把前端传过来的字符串,作为函数名执行哈,咱们可以把它这样等价:
    eval(item).delay(x,y) == add.delay(x,y)
    另外,确实这段代码是放在一个任务函数里去调用的,用不用 delay 都出现了这种情况。
    akmonde
        14
    akmonde  
    OP
       2017-05-18 20:34:34 +08:00
    @pkking 感谢回复,不过小弟学识有限,没有理解您的意思,您能稍微举个例子么?
    zsz
        15
    zsz  
       2017-05-18 20:52:38 +08:00 via iPhone
    @akmonde
    加我们的群问效率高些,一群工程师组建的面向初学者的
    Python Linux 学习群,qq 群号:278529278,
    Php Linux 学习群,qq 群号:476648701,
    非商业性质,拒绝广告,只接收真正想学这方面技术的朋友,交流学习,申请请说明来自 v2ex
    r0okit
        16
    r0okit  
       2017-05-19 12:56:12 +08:00
    @akmonde @pkking 他说的没错,你这个逻辑不对,最好是改用 chain,而不是在一个任务里面调用另一个任务,官网中有对这个的介绍,还有你可以用个字典名字映射函数,不要用 eval,外部传入的都不可信
    akmonde
        17
    akmonde  
    OP
       2017-05-19 13:38:38 +08:00
    @r0okit eval 之前已经对能执行恶意命令的特殊字符进行了过滤,也不涉及库查询,所以应该不会有安全方面的问题。
    我去研究下 chain 和怎么用字典名字映射函数,先谢谢您。
    这问题也是够折腾的,这两天在一步步替换正常的配置和代码进行对比,真是头疼,问题出现的有点隐蔽。
    r0okit
        18
    r0okit  
       2017-05-19 15:16:48 +08:00
    @akmonde 我再啰嗦下,eval 你是防不住的,相信我,只要你放到生产环境上,各种猥琐的注入方法会让你大开眼界
    akmonde
        19
    akmonde  
    OP
       2017-05-20 08:10:01 +08:00
    @r0okit @pkking 非常感谢大牛们的指导,确实黑名单难以过滤完全特殊字符。另外我似乎查出问题所在了,确实是 result.ready()是放在 delay()任务中执行,那里就会阻塞运行不下去了。
    我这边前端采用了 flower 的接口控制任务的启动,话说 flower 有参数可以不调用 delay 么?
    另外,我试了下如果不调用 delay 的话,不使用 chain 也是可以用的。
    是否 flower 前端传过来的参数是必须调用 delay,然后必须用 chain 或者 signature 之类的才能破?
    akmonde
        20
    akmonde  
    OP
       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 呢?这好像是个悖论,没想明白应该怎么弄。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1029 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 22:22 · PVG 06:22 · LAX 15:22 · JFK 18:22
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.