Python分布式任务队列Celery突然报错"ResultHandler' crashed OSError('handle is closed')",请教一下各位

好好跑着的代码,国庆回来突然报错,报错内容是:

ERROR/ForkPoolWorker-7] Thread 'ResultHandler' crashed: OSError('handle is closed',)
Traceback (most recent call last):
  File "/root/kvenv/lib/python2.7/site-packages/billiard/pool.py", line 478, in run
    return self.body()
  File "/root/kvenv/lib/python2.7/site-packages/billiard/pool.py", line 866, in body
    self.finish_at_shutdown()
  File "/root/kvenv/lib/python2.7/site-packages/billiard/pool.py", line 883, in finish_at_shutdown
    ready, task = poll(1.0)
  File "/root/kvenv/lib/python2.7/site-packages/billiard/pool.py", line 1326, in _poll_result
    if self._outqueue._reader.poll(timeout):
  File "/root/kvenv/lib/python2.7/site-packages/billiard/connection.py", line 285, in poll
    self._check_closed()
  File "/root/kvenv/lib/python2.7/site-packages/billiard/connection.py", line 165, in _check_closed
    raise OSError("handle is closed")
OSError: handle is closed
ERROR/MainProcess] Process 'ForkPoolWorker-7' pid:31664 exited with 'exitcode 1'

查了一上午的 google,只有 celery 的一个 git issue 是一样的报错,里面提到是 gevent 的问题。排查了自己的代码,只有一个地方用到了 gevent,所以 gevent 可能是一个原因。但是奇怪的是,之前一直都没报错过,然后重启程序之后也正常了。

请问各位大佬:是否有同样碰到过这种问题的,如果有解决方案万分感谢。

目前准备舍弃 celery,简单用 mq 来做任务的分发了。被坑了两三次了,在这样下去 kpi 没了。

感谢各位。


Python分布式任务队列Celery突然报错"ResultHandler' crashed OSError('handle is closed')",请教一下各位

14 回复

看来大佬们用 2. 7 的还很多呀


这个错误通常是因为Celery的结果后端连接(比如Redis)在任务执行过程中被意外关闭了。最常见的情况是任务执行时间太长,超过了连接的超时时间,或者网络不稳定导致连接中断。

检查一下你的任务执行时间是否过长。如果任务需要运行很长时间,可以考虑增加Redis或其他结果后端的连接超时设置。另外,确保你的网络连接稳定,避免因为网络问题导致连接断开。

这里是一个简单的示例,展示如何配置Celery以使用Redis作为结果后端,并设置合理的超时时间:

from celery import Celery

app = Celery('myapp')

# 配置Redis作为结果后端,设置连接超时和重试参数
app.conf.update(
    broker_url='redis://localhost:6379/0',
    result_backend='redis://localhost:6379/0',
    # 增加连接超时时间(秒)
    broker_connection_timeout=30,
    result_backend_transport_options={
        'retry_policy': {
            'timeout': 5.0  # 操作超时时间
        },
        'socket_keepalive': True,  # 保持连接活跃
        'socket_timeout': 30,  # socket超时时间
    },
    # 如果任务执行时间很长,考虑增加这个值
    worker_prefetch_multiplier=1,
    worker_max_tasks_per_child=1000,
)

@app.task
def long_running_task():
    import time
    # 模拟长时间运行的任务
    time.sleep(60)  # 这个任务需要运行60秒
    return "任务完成"

if __name__ == '__main__':
    app.start()

如果问题依然存在,可以考虑在任务代码中添加重试逻辑,或者在任务开始前检查连接状态。另外,确保你的Celery worker和结果后端(如Redis)版本兼容。

总结:检查连接超时和网络稳定性。

历史遗留问题,抱歉抱歉。

ll /proc/<pid>/fd 看一下
ulimit -n 看一下
你的任务是否设置了超时
感觉像是 socket 文件被关闭了

celery 一定要做进程存活的监控。

不建议任何人在面向用户的服务上使用 celery,非常多的坑,尤其是进程假死的问题

那推荐使用什么呢?

用 kombu 自己做简单封装,排查问题会简单很多,基本封装看下这里 https://zhuanlan.zhihu.com/p/43264903

感谢。下次复现的时候瞄一眼。
检查了下,任务没有设置超时。
ulimit -n 是 4200,正常运行的时候 lsof 看了下能到 3500,所以不排除有这个的原因。
再次感谢。



感谢两位。
之前碰见过假死,所以后面设置了定时任务,每隔一段时间杀死所有的 celery 的进程,苟一苟。因为用了 supervisor,杀了之后,supervisor 会再拉起来。
不知道这样会不会出现问题。

哈哈哈,跟我们之前一样,然后要问一下,你这个定时任务是怎么做的?假如这个定时任务进程挂了呢?再起个定时任务监控这个定时任务吗

感谢


目前搞的比较简单,写了 bash 脚本通过 crontab 来定时调用。
只不过您提出来的确实是个风险点。
目前这边也是准备用 rabbitmq 自己封装下了,不然这个时不时出问题太难受了。
万分感谢

都说了要用 openstack 的 oslo_message
用什么鬼 celery

找不到问题就是代码没读透!

回到顶部