我有一个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守护程序初始化脚本启动我的worker时才会发生这种情况:
# /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 init脚本/etc/init.d/celeryd是Celery文档指出的标准脚本。)
如果我从命令行启动worker和队列,则会发送电子邮件而不会出现任何错误:
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邮件配置为使用第三方电子邮件服务:
# /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
...
我试着取消注释" os.environ.setdefault" celeryapp.py中的命令认为Celery需要明确指向设置文件,但是当我这样做并尝试通过我的celeryd脚本使用命令" sudo service celeryd start"启动celery时,工作人员赢了' t启动,但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"
...
任何人都可以看到我做错了吗?
谢谢!
答案 0 :(得分:0)
这是因为你的工作人员根本不是Django应用程序,只有你的调度员才是。用于SMTP的Django配置实际上是用于直接从Django视图或Django信号处理程序的上下文发送电子邮件。 实际上,您需要做的是使用工作进程中的smtplib发送电子邮件,不要尝试读取django配置文件。相反,工作进程应该从类似JSON文件
的内容中读取SMTP配置参数