【问题标题】:Unable to email in Django via Celery worker when using System V init script使用 System V 初始化脚本时,无法通过 Celery worker 在 Django 中发送电子邮件
【发布时间】:2015-07-06 02:21:33
【问题描述】:

我有一个 Django 1.6.2 应用程序,我正在使用 Celery 3.1.7 和 RabbitMQ 2.8.4 来处理异步任务。我的问题是,如果电子邮件是通过 Celery 工作队列发送的,我将无法使用 Django 的 send_mail 函数发送电子邮件。当我执行这个 send_email 任务时...

# apps.photos.tasks.py
from __future__ import absolute_import
from django.core.mail import send_mail
from conf.celeryapp import app

@app.task
def send_email():
    send_mail('Test Email',
        'This is a test email.',
        'me@example.com',
        ['me2@example.com'],
        fail_silently=False)

通过我的 Python 解释器中的这个命令...

>>> from apps.photos.tasks import send_email
>>> result = send_email.delay()

我收到以下错误:

[2015-04-24 15:13:48,371: ERROR/MainProcess] Task apps.photos.tasks.send_email[db303245-f36c-4ae2-9d72-86d2bbbbd358] raised unexpected: ImproperlyConfigured('Requested setting EMAIL_BACKEND, but settings are not configured. You must either define the environment variable DJANGO_SETTINGS_MODULE or call settings.configure() before accessing settings.',)
Traceback (most recent call last):
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/celery/app/trace.py", line 240, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/celery/app/trace.py", line 438, in __protected_call__
    return self.run(*args, **kwargs)
  File "apps/photos/tasks.py", line 34, in send_email
    fail_silently=False)
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/django/core/mail/__init__.py", line 48, in send_mail
    fail_silently=fail_silently)
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/django/core/mail/__init__.py", line 29, in get_connection
    klass = import_by_path(backend or settings.EMAIL_BACKEND)
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/django/conf/__init__.py", line 54, in __getattr__
    self._setup(name)
  File "/home/myproj/venv/myproj/local/lib/python2.7/site-packages/django/conf/__init__.py", line 47, in _setup
    % (desc, ENVIRONMENT_VARIABLE))

环境变量 DJANGO_SETTINGS_MODULE 在我的虚拟环境中设置。

只有当我通过这个 celery 守护进程初始化脚本启动我的工作人员时才会发生这种情况:

# /etc/default/celeryd
CELERYD_NODES="worker1 worker2 worker3"
CELERY_BIN="/home/myproj/venv/myproj/bin/celery"
CELERY_APP="conf.celeryapp:app"
CELERYD_CHDIR="/www/myproj"
CELERYD_OPTS="--time-limit=300 --concurrency=8 --config=celeryconfig -Q:1 default -Q:2 photos -Q:3 mail"
CELERYD_USER="celery"
CELERYD_GROUP="celery"

(我的 Celery 初始化脚本 /etc/init.d/celeryd 是 Celery 文档所指向的标准脚本。)

如果我从命令行启动工作程序和队列,则电子邮件发送没有任何错误:

celery worker -A conf.celeryapp:app -n worker3 -Q mail -l info 

这是我的 celeryconfig 文件:

# /www/myproj/conf/celeryconfig.py
from kombu import Queue, Exchange

BROKER_URL = 'amqp://'
CELERY_RESULT_BACKEND = 'amqp://'
CELERY_DEFAULT_QUEUE = 'default'
CELERY_QUEUES = (
    Queue('default', Exchange('default'), routing_key='default'),
    Queue('photos', Exchange('photos'), routing_key='photos'),
    Queue('mail', Exchange('mail'), routing_key='mail'),
)
CELERY_ROUTES = (
    {'apps.photos.tasks.hello': {'queue': 'default', 'routing_key': 'default'}},
    {'apps.photos.tasks.add': {'queue': 'photos', 'routing_key': 'photos'}},
    {'apps.photos.tasks.send_email': {'queue': 'mail', 'routing_key': 'mail'}},
)

此文件初始化 Celery 应用程序:

# /www/myproj/conf/celeryapp.py
from celery import Celery

#import os
#os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'conf.settings.prod')

app = Celery('celeryapp')
app.config_from_object('conf.celeryconfig')
app.autodiscover_tasks(['apps.photos'])

这些设置将我的 Django 邮件配置为使用第 3 方电子邮件服务:

# /www/myproj/conf/settings/base.py
...
EMAIL_HOST = 'smtp.sendgrid.net'
EMAIL_HOST_USER = get_env_variable('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = get_env_variable('EMAIL_HOST_PASSWORD')
EMAIL_PORT = 587
EMAIL_USE_TLS = True
SITE_EMAIL = 'admin@example.com'
RECIPIENTS = ['me@example.com', ]
FAIL_SILENTLY = False
...

我尝试取消注释 celeryapp.py 中的“os.environ.setdefault”命令,认为 Celery 需要明确指示设置文件,但是当我这样做并尝试通过我的 celeryd 脚本使用命令“sudo service celeryd”启动 celery start”,worker 根本不会启动,但 Celery 不会显示任何错误,即使我将 loglevel 设置为“debug”。

我还尝试在我的设置文件中明确设置 EMAIL_BACKEND 变量以及 send_email 函数本身...

settings.EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'

但这并没有解决错误。

此外,我在 /etc/default/celeryd 文件中添加了以下内容,但无济于事:

# /etc/default/celeryd
...
export DJANGO_SETTINGS_MODULE="conf.settings.prod"
...

谁能看出我做错了什么?

谢谢!

【问题讨论】:

    标签: python django email celery


    【解决方案1】:

    这是因为您的工作人员根本不是 Django 应用程序,只有您的调度员才是。 SMTP 的 Django 配置实际上是为了直接从 Django 视图或 Django 信号处理程序的上下文发送电子邮件。 实际上,您需要做的是使用工作进程中的smtplib 发送电子邮件,并且不要尝试读取 django 配置文件。相反,工作进程应该从 JSON 文件之类的文件中读取 SMTP 配置参数

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-05-16
      • 1970-01-01
      • 2014-08-04
      • 2019-06-04
      • 2018-10-19
      • 1970-01-01
      • 1970-01-01
      • 2018-02-15
      相关资源
      最近更新 更多