You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 03:08:24