Django+Celery+Docker环境下邮件发送任务未执行问题排查
Django+Celery任务未执行问题排查与解决方案
问题描述
我在Django中编写了视图函数,接收用户提交的邮件发送数据(发件人、主题、内容等)POST请求,将数据传递给Celery任务,通过Django标准send_mail函数发送邮件,但Celery任务始终未执行。
技术栈
- Django
- Redis
- Celery
- Docker
项目结构
sender - sender -- __init__.py -- asgi.py -- celery.py -- settings.py -- urls.py -- wsgi.py - emails -- migrations -- __init__.py -- admin.py -- apps.py -- forms.py -- models.py -- tasks.py -- tests.py -- views.py - templates - venv - db.sqlite3 - docker-compose.yml - Dockerfile - manage.py
相关代码片段
views.py
from django.shortcuts import render, redirect from .tasks import * from .models import * from .forms import * def send_some_email(request): if request.method == 'POST': form = EmailForm(request.POST) if form.is_valid(): from_mail = form.cleaned_data['from_mail'] subject = form.cleaned_data['subject'] message = form.cleaned_data['message'] cat = form.cleaned_data['cat'] limit = form.cleaned_data['limit'] try: send.delay(from_mail, subject, message, cat, limit) return redirect('home') except Exception as ex: print(ex) return redirect('errorpage') else: form = EmailForm() return render(request, 'emails/index.html', {'form': form})
tasks.py
from celery import shared_task from .forms import * from django.core.mail import send_mail @shared_task def send(from_mail, subject, message, cat, limit): for element in Emails.objects.filter(active=True, category__name=cat)[:limit]: send_mail(subject=subject, from_email=from_mail, message=message, recipient_list=[str(element), ]) print(str(element)) element.active = False element.save() return True
Dockerfile
FROM python:3.9 WORKDIR /apps COPY requirements.txt /apps RUN pip install -r requirements.txt COPY . /apps EXPOSE 8000 CMD ["python", "manage.py", "migrate"] CMD ["2525"]
docker-compose.yml
version: "3.9" services: redis: image: redis restart: always sender: restart: always build: context: . ports: - "8000:8000" command: ["python", "manage.py", "runserver", "0.0.0.0:8000"] depends_on: - redis worker: build: context: . restart: always command: ['celery', '-A', 'sender', 'worker', '-P', 'solo'] depends_on: - redis
celery.py
import os from celery import Celery os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'sender.settings') app = Celery('sender') app.config_from_object('django.conf:settings', namespace='CELERY') app.autodiscover_tasks() @app.task(bind=True) def debug_task(self): print(f'Request: {self.request!r}')
sender/sender/init.py
from .celery import app as celery_app __all__ = ('celery_app',)
已尝试操作
在启动Celery Worker时添加-P solo参数(Windows环境),但问题仍未解决。
排查与解决步骤
1. 修正Celery与Redis的连接配置
确保Django settings.py中配置了容器内可访问的Redis地址:
CELERY_BROKER_URL = 'redis://redis:6379/0' CELERY_RESULT_BACKEND = 'redis://redis:6379/0'
docker-compose中redis服务名为redis,容器内需用服务名而非localhost访问。
2. 修复Dockerfile的CMD执行问题
Dockerfile中多个CMD只会执行最后一个,导致数据库迁移命令失效。修改方案:
- 移除Dockerfile中多余的
CMD行 - 在docker-compose的
sender服务中合并命令:command: bash -c "python manage.py migrate && python manage.py runserver 0.0.0.0:8000"
数据库未迁移会导致任务中查询模型出错,引发静默失败。
3. 查看Celery Worker日志定位错误
执行命令查看worker容器日志:
docker-compose logs worker
重点关注:
- Redis连接失败提示
- 任务未找到的报错
- 数据库访问权限或路径问题
4. 验证任务是否被注册
在worker容器中执行命令,确认任务已被发现:
docker-compose exec worker celery -A sender inspect registered
如果看不到emails.tasks.send,检查:
emails应用是否添加到settings.INSTALLED_APPS- 任务文件名是否为
tasks.py(Celery默认只识别该文件名) shared_task装饰器是否正确使用
5. 增强任务的可调试性
在tasks.py的任务函数开头添加打印语句,确认任务是否被触发:
@shared_task def send(from_mail, subject, message, cat, limit): print(f"任务触发:发件人={from_mail},分类={cat},数量={limit}") # 原有代码...
同时给worker添加日志级别参数,查看更详细输出:
command: ['celery', '-A', 'sender', 'worker', '-P', 'solo', '--loglevel=info']
6. 处理Windows Docker环境特殊问题
- 确保项目目录未被Windows Defender等安全软件拦截
- 检查docker-compose的volume配置(如果有),确保代码同步到容器
- 避免多个容器共享sqlite数据库(sqlite不适合多进程/多容器场景,建议替换为PostgreSQL)
内容的提问来源于stack exchange,提问作者Atom
相关产品推荐
相关产品推荐

