2015-04-03 109 views
0

我試圖在Django 1.6.2應用程序中使用django-celery-email和Celery 3.1.17以RabbitMQ 3.5.0作爲我的消息代理和結果後端發送異步電子郵件。電子郵件正在發送和接收,但在發送電子郵件時,我的Celery日誌中也收到錯誤「django.core.mail ...不是JSON序列化」。我在Celery中使用JSON進行序列化,因爲pickle已經被棄用了。有什麼方法可以更改我的配置以防止發生此錯誤?順便說一下,當我不使用芹菜的延遲方法時,我可以發送電子郵件。如何使用Celery在Django中發送異步電子郵件?

謝謝。

# Stacktrace 
Task app.tasks.send_email with id 7ac1eb8e-c090-4893-8147-1f204e463d12 raised exception: 
'EncodeError(TypeError("<module \'django.core.mail\' from \'/Users/me/venv/django/lib/python2.7/site-packages/django/core/mail/__init__.pyc\'> is not JSON serializable",),)' 


Task was called with args: [] kwargs: {}. 

The contents of the full traceback was: 

Traceback (most recent call last): 
File "/Users/me/venv/django/lib/python2.7/site-packages/celery/app/trace.py", line 283, in trace_task 
    uuid, retval, SUCCESS, request=task_request, 
File "/Users/me/venv/django/lib/python2.7/site-packages/celery/backends/amqp.py", line 136, in store_result 
    delivery_mode=self.delivery_mode, 
File "/Users/me/venv/django/lib/python2.7/site-packages/kombu/messaging.py", line 161, in publish 
    compression, headers) 
File "/Users/me/venv/django/lib/python2.7/site-packages/kombu/messaging.py", line 237, in _prepare 
    body) = dumps(body, serializer=serializer) 
File "/Users/me/venv/django/lib/python2.7/site-packages/kombu/serialization.py", line 164, in dumps 
    payload = encoder(data) 
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/contextlib.py", line 35, in __exit__ 
    self.gen.throw(type, value, traceback) 
File "/Users/me/venv/django/lib/python2.7/site-packages/kombu/serialization.py", line 59, in _reraise_errors 
    reraise(wrapper, wrapper(exc), sys.exc_info()[2]) 
File "/Users/me/venv/django/lib/python2.7/site-packages/kombu/serialization.py", line 55, in _reraise_errors 
    yield 
File "/Users/me/venv/django/lib/python2.7/site-packages/kombu/serialization.py", line 164, in dumps 
    payload = encoder(data) 
File "/Users/me/venv/django/lib/python2.7/site-packages/anyjson/__init__.py", line 141, in dumps 
    return implementation.dumps(value) 
File "/Users/me/venv/django/lib/python2.7/site-packages/anyjson/__init__.py", line 87, in dumps 
    return self._encode(data) 
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/__init__.py", line 243, in dumps 
    return _default_encoder.encode(obj) 
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 207, in encode 
    chunks = self.iterencode(o, _one_shot=True) 
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 270, in iterencode 
    return _iterencode(o, 0) 
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/json/encoder.py", line 184, in default 
    raise TypeError(repr(o) + " is not JSON serializable") 
EncodeError: <module 'django.core.mail' from '/Users/me/venv/django/lib/python2.7/site-packages/django/core/mail/__init__.pyc'> is not JSON serializable 

# settings.py 
# MAIL SETTINGS 
EMAIL_HOST = 'smtp.sendgrid.net' 
EMAIL_HOST_USER = 'me' 
EMAIL_HOST_PASSWORD ='password' 
EMAIL_PORT = 587 
EMAIL_USE_TLS = True 
FAIL_SILENTLY = False 

# CELERY SETTINGS 
BROKER_URL = 'amqp://[email protected]//' 
CELERY_RESULT_BACKEND = 'amqp' 
CELERY_TASK_SERIALIZER = 'json' 
CELERY_RESULT_SERIALIZER = 'json' 
CELERY_ACCEPT_CONTENT = ['json', ] 

# DJANGO-CELERY-EMAIL 
INSTALLED_APPS += ('djcelery_email',) 
EMAIL_BACKEND = 'djcelery_email.backends.CeleryEmailBackend' 

# tasks.py 
from __future__ import absolute_import 

import smtplib 
from conf.celery import app 
from django.core import mail 
from django.template.loader import render_to_string 

@app.task 
def send_email(): 
    to_email = '[email protected]' 
    subject = 'Testing Celery/RabbitMQ' 
    from_email = '[email protected]' 
    message = 'This is a test of my Celery/RabbitMQ function.' 
    recipient_list = [] 
    recipient_list.append(to_email) 
    html_message = render_to_string('send_mail.html', {'message': message}) 
    try: 
     mail.send_mail(subject, message, from_email, recipient_list, html_message) 
    except smtplib.SMTPException, e: 
     return 0 
    return mail 

# views.py 
from app.tasks import send_email 
def home_page(request, template): 
    # Send mail synchronously 
    #send_email() 
    # Send email asynchronously. 
    send_email.delay() 
    return render(request, template) 

回答

0

您會收到預期的錯誤。 Celery設置爲使用JSON序列化,並使用內置的json庫來嘗試序列化django.core.mail,這顯然不支持任何形式的序列化。

它調用時沒有delay的原因是因爲它的工作方式類似於調用一個典型的函數(在同一個進程中)。

如果您必須從任務返回某些內容,則可以返回支持序列化的值或對象的字典。對於自定義序列化,您可以使用serializer屬性,並在調用任務時傳遞自定義解碼器/編碼器。

在你的情況下,你可以返回類似{'success': True}和任何失敗的False值。

使用自定義序列More options

+0

我用芹菜,芹菜的Django(Django的芹菜),和Django的郵政局(Django的post_office)發送電子郵件嘗試和發現,電子郵件不會被髮送,除非我註釋掉了CELERY_ACCEPT_CONTENT ['json'],CELERY_TASK_SERIALIZER和CELERY_RESULT_SERIALIZER,我不喜歡這樣做,因爲芹菜希望您避免使用泡菜。我希望Django核心團隊會推薦一種標準的方式發送異步郵件。 – William 2015-04-04 16:54:31

+0

我已經解決了另一個只使用芹菜和Django郵局的解決方案。我使用DPO作爲我的郵件傳遞機制,然後使用Celery的Beat調度程序每隔30秒安排一次任務以運行DPO的send_queued_mail。它讓我解決了我在我的問題中討論的問題。 – William 2015-04-04 23:33:19