DigitalOcean上Django项目Celery任务已接收但无执行日志问题
问题描述
在DigitalOcean的Ubuntu 22.04 Droplet上部署集成Celery的Django项目时,出现以下异常:
- Celery Worker仅打印任务接收日志,无任务执行完成的默认日志输出
- 通过
AsyncResult查询任务状态为SUCCESS,且返回结果正确 - 服务器Redis启用了
requirepass认证,本地环境无此配置,这是本地与服务器的唯一差异
相关代码与日志
任务代码(来自django-cookiecutter)
from django.contrib.auth import get_user_model from config import celery_app User = get_user_model() @celery_app.task() def get_users_count(): return User.objects.count()
Worker启动命令
celery -A config.celery_app worker --loglevel=DEBUG --without-gossip --without-mingle --without-heartbeat -Ofair --pool=solo
任务执行与Worker日志
通过Django Shell执行任务:
get_users_count.delay() <AsyncResult: 821982b7-f256-462b-869c-e415da168c3f>
Worker仅输出任务接收日志:
[2023-10-06 23:57:25,568: INFO/MainProcess] Task myapp.users.tasks.get_users_count[821982b7-f256-462b-869c-e415da168c3f] received
自定义日志测试
添加自定义日志后的任务代码:
import logging logger = logging.getLogger(__name__) @celery_app.task() def get_users_count(): """A pointless Celery task to demonstrate usage.""" logger.info("get_users_count task executed") count = User.objects.count() logger.info(f"user count is {count}") return count
Worker日志显示自定义日志,但仍无默认任务完成日志:
[2023-10-07 05:09:37,810: INFO/MainProcess] Task myapp.users.tasks.get_users_count[474736b2-d568-45f6-ae34-f512612cca2f] received [2023-10-07 05:09:37,811: INFO/MainProcess] get_users_count task executed [2023-10-07 05:09:37,821: INFO/MainProcess] user count is 2
依赖版本
celery==5.3.1 django-celery-beat==2.5.0 Django==4.2.3
原因分析
核心原因是Celery默认的任务完成日志依赖结果后端的状态反馈,而Redis启用密码认证后,Worker未正确配置结果后端的认证信息,导致Worker无法向Redis写入任务完成状态的同时,抑制了默认完成日志的输出。
尽管任务实际执行成功并返回结果,但Worker尝试写入Redis状态时遇到认证问题,而Celery未抛出明显错误,仅跳过了默认完成日志的打印。另外,--without-heartbeat参数可能影响Worker的状态报告逻辑,但结合自定义日志正常输出的情况,Redis认证配置缺失是主要诱因。
解决方法
1. 配置Celery结果后端的Redis认证信息
在Django配置文件(如settings.py)或Celery配置文件(config/celery_app.py)中,确保Broker和结果后端的URL包含Redis密码:
# config/celery_app.py 或 settings.py CELERY_BROKER_URL = 'redis://:your_redis_password@localhost:6379/0' CELERY_RESULT_BACKEND = 'redis://:your_redis_password@localhost:6379/0'
注意URL格式:redis://:密码@主机:端口/数据库编号,密码前的冒号不能省略。
2. 调整Worker启动参数
移除可能干扰状态报告的--without-heartbeat参数,重新启动Worker:
celery -A config.celery_app worker --loglevel=DEBUG --without-gossip --without-mingle -Ofair --pool=solo
心跳机制能保证Worker与Broker的连接稳定,避免潜在的状态同步问题。
3. 验证Redis连接
通过Redis客户端确认密码配置正确:
redis-cli -a your_redis_password 127.0.0.1:6379> ping PONG
确保Worker进程能正常访问Redis,无权限或网络问题。
4. 强制开启Celery核心日志(可选)
若上述步骤无效,在Celery配置文件中添加日志配置,强制开启核心日志输出:
CELERY_LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console': { 'class': 'logging.StreamHandler', }, }, 'loggers': { 'celery': { 'handlers': ['console'], 'level': 'INFO', 'propagate': True, }, }, }
内容的提问来源于stack exchange,提问作者user21169813

