一、问题
下面的问题,都来自同一个周期任务:每隔3分钟,统一命名为 per_three_task
- 有一天,周期任务一直在跑,早上还是正常,但是到了下面,per_three_task就没有动静了,其他周期任务正常执行,抛异常。
- 客户现场,因为某些原因导致celery worker不执行,rabbitmq中堆积了大量per_three_task未消费的消息,重新部署之后,per_three_task疯狂执行,然后里面抛异常。
异常信息:Too many heartbeats missed
二、原因分析
查了各种资料,发现celery确实存在这个问题,但是没有能从配置上解决该问题
最终结合实际分析,猜测这个问题的原因可能是:
- 有很多旧的定时任务堆积在rabbitmq的消息队列中,celery worker在处理这些任务的时候没有发送足够的心跳
- 经过本地环境模拟复现,轮询worker如果一次性处理的数据量比较多,执行时间会比较长,长时间没有消费消息队列中的消息,消息队列通过心跳判断该woker已经挂了,不再调用该woker。
后来查看celery的issue:https://github.com/celery/celery/issues/5157,大家的猜测差不多
原因很可能是worker执行时间太长导致的
三、解决措施
- 优化worker执行逻辑,让worker的执行时间缩短
- 给worker函数per_three_task加上一个装饰器,当woker执行时,判断上次执行是否结束,如果未结束,直接return,及时消费消息队列中的消息