djcelery的定时任务问题

时间:2021-10-23 07:49:37

    前几天在工作中遇到djcelery定时任务失效的问题,查了好几天,最终定位解决,整理分享下

    首先简单介绍下djcelery定时任务的框架,估计了解它的人都很熟悉,如下图

djcelery的定时任务问题

    其实简单的说就是celery的beat定时将任务发给消息中间件(这里用的是rabbitmq队列),rabbitmq将定时任务发送给celery worker去执行(即django中的task),最终将检测结果存储的过程。

    关于celery的详细介绍可见http://python.jobbole.com/87086/

    问题现象如下:

    发现一直正常运行的定时任务没有正常执行,而celery的worker和beat进程都在后台运行中,即如下的进程是存在的

djcelery的定时任务问题

    故曾经的运维经验告诉我要重启,所以,第一招,重启celery的worker和beat进程,但发现问题依旧,也就是说这个问题没法通过守护进程的方式避免。

    那第二招就是看日志了,查看worker的日志,发现其实worker已经准备好,但一直没有真正去执行任务

djcelery的定时任务问题

    下一步就是查看发生任务的消息中间件了,就是神奇的rabbitmq,rabbitmq的情况可在网页查看,如下图

djcelery的定时任务问题

djcelery的定时任务问题

    可以明显的看到queue message是没有数据的,但message rates却是有数据的(这个点其实还是没弄清到底是为什么,欢迎比较懂的同学指点)

    故尝试手动执行celery beat和worker,rabbitmq是否能收到任务,发现在djcelery的任务没有发送到rabbitmq中,手动编写测试task程序

celeryconfig.py

import sys
import os
sys.path.insert(0, os.getcwd())

CELERY_IMPORTS = ("tasks", )

CELERY_RESULT_BACKEND = "amqp"

BROKER_HOST = "localhost"
BROKER_PORT = 5672
BROKER_USER = "guest"
BROKER_PASSWORD = "guest"
BROKER_VHOST = "/"

tasks.py

from celery.task import task
from celery import Celery, platforms

platforms.C_FORCE_ROOT = True
@task
def add(x, y):
    return x + y
                  

    执行任务,发现rabbitmq可以接受到消息,由于之前对队列的了解相当少,这里也请教了些对队列比较了解的同学,都觉得应该是消费者配置的问题,但查了django的setting没看到异常。

    查了下网上关于rabbitmq的资料,大概是生产者通过exchange将消息按照规则发送给对应的队列,而我们的队列是没有收到消息的,修改了exchange规则调试,确实队列中会收到消息,但这个队列不是我们系统制定的队列。

    在和rabbitmq纠缠了好久后,各种执行celery的命令,发现手动单独执行celery beat时会出现如下报错

djcelery的定时任务问题

    怀疑与定时任务有关,查看了报错的celery的schedules.py文件中报错的位置,初步判断是定时任务设定的问题,通过django的admin查看Periodic task的任务设置情况,发现有一个测试任务没有设置crontab和Interval,之前就遇到过当进入到这个页面,如果两个都不设置报错就会报错的情况,故将interval改为定时监测时间,crontab不设置后,celery worker日志中有数据了,rabbitmq的队列也恢复正常了。

djcelery的定时任务问题

 

    其实这个问题在这个文档中有一些说明

https://my.oschina.net/kinegratii/blog/292395?fromerr=2lvw3H0L

djcelery的定时任务问题

    定时任务的重点在于必须有且仅有interval和crontab中的其一设置,即不能同时设置也不能同时不设置

djcelery的定时任务问题

    celery很强大,更多的情况可直接参考上述的两个文档,基本够用了

    而为什么会出现测试任务的定时设置的crontab和interval都为空的情况呢?由于我们的系统使用的开源项目为页面式的,在调试新功能时增加的测试任务,而修改没有涉及到后续任务执行情况的改动,故没有在admin页面设定interval和crontab,导致celery beat启动报错。

    为了避免这类的问题再次出现,进行如下的一些改进

    1、在系统页面中增加添加任务后自动设置默认的crontab和interval(省得人工去django的admin改,当然,django的admin很强大)

    2、增加celery beat单独的日志

 

    最后,无变更不故障,这句话我是真的体会到了