2017-05-14 60 views
0

我想用Celery和RabbitMQ異步發送電子郵件。這是我第一次使用芹菜,所以我不太熟悉一些錯誤。我意識到追溯來自一個名爲kombu的包,我知道它是Celery的依賴。我只是無法調試。kombu.exceptions.EncodeError:<Flask 'src'>不是JSON可序列化

每當我測試出試圖發送電子郵件時,都會發生回溯。

回溯:

[2017-05-14 12:35:08,093] ERROR in app: Exception on /home [POST] 
Traceback (most recent call last): 
    File "/Users/kai/github-projects/Ticket-System/venv/lib/python3.5/site-packages/kombu/serialization.py", line 50, in _reraise_errors 
    yield 
    File "/Users/kai/github-projects/Ticket-System/venv/lib/python3.5/site-packages/kombu/serialization.py", line 221, in dumps 
    payload = encoder(data) 
    File "/Users/kai/github-projects/Ticket-System/venv/lib/python3.5/site-packages/kombu/utils/json.py", line 72, in dumps 
    **dict(default_kwargs, **kwargs)) 
    File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/json/__init__.py", line 237, in dumps 
    **kw).encode(obj) 
    File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/json/encoder.py", line 198, in encode 
    chunks = self.iterencode(o, _one_shot=True) 
    File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/json/encoder.py", line 256, in iterencode 
    return _iterencode(o, 0) 
    File "/Users/kai/github-projects/Ticket-System/venv/lib/python3.5/site-packages/kombu/utils/json.py", line 62, in default 
    return super(JSONEncoder, self).default(o) 
    File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/json/encoder.py", line 179, in default 
    raise TypeError(repr(o) + " is not JSON serializable") 
TypeError: <Flask 'src'> is not JSON serializable 

During handling of the above exception, another exception occurred: 

Traceback (most recent call last): 
    File "/Users/kai/github-projects/Ticket-System/venv/lib/python3.5/site-packages/flask/app.py", line 1982, in wsgi_app 
    response = self.full_dispatch_request() 
    File "/Users/kai/github-projects/Ticket-System/venv/lib/python3.5/site-packages/flask/app.py", line 1614, in full_dispatch_request 
    rv = self.handle_user_exception(e) 
    File "/Users/kai/github-projects/Ticket-System/venv/lib/python3.5/site-packages/flask/app.py", line 1517, in handle_user_exception 
    reraise(exc_type, exc_value, tb) 
    File "/Users/kai/github-projects/Ticket-System/venv/lib/python3.5/site-packages/flask/_compat.py", line 33, in reraise 
    raise value 
    File "/Users/kai/github-projects/Ticket-System/venv/lib/python3.5/site-packages/flask/app.py", line 1612, in full_dispatch_request 
    rv = self.dispatch_request() 
    File "/Users/kai/github-projects/Ticket-System/venv/lib/python3.5/site-packages/flask/app.py", line 1598, in dispatch_request 
    return self.view_functions[rule.endpoint](**req.view_args) 
    File "/Users/kai/github-projects/Ticket-System/src/views.py", line 139, in home 
    email_notification(cust_f_name, cust_email, tix_num) 
    File "/Users/kai/github-projects/Ticket-System/src/notifications.py", line 71, in email_notification 
    c_name=cust_name, tix=tix)) 
    File "/Users/kai/github-projects/Ticket-System/src/notifications.py", line 54, in send_email 
    send_async_email.delay(app, msg) 
    File "/Users/kai/github-projects/Ticket-System/venv/lib/python3.5/site-packages/celery/app/task.py", line 412, in delay 
    return self.apply_async(args, kwargs) 
    File "/Users/kai/github-projects/Ticket-System/venv/lib/python3.5/site-packages/celery/app/task.py", line 535, in apply_async 
    **options 
    File "/Users/kai/github-projects/Ticket-System/venv/lib/python3.5/site-packages/celery/app/base.py", line 737, in send_task 
    amqp.send_task_message(P, name, message, **options) 
    File "/Users/kai/github-projects/Ticket-System/venv/lib/python3.5/site-packages/celery/app/amqp.py", line 558, in send_task_message 
    **properties 
    File "/Users/kai/github-projects/Ticket-System/venv/lib/python3.5/site-packages/kombu/messaging.py", line 169, in publish 
    compression, headers) 
    File "/Users/kai/github-projects/Ticket-System/venv/lib/python3.5/site-packages/kombu/messaging.py", line 252, in _prepare 
    body) = dumps(body, serializer=serializer) 
    File "/Users/kai/github-projects/Ticket-System/venv/lib/python3.5/site-packages/kombu/serialization.py", line 221, in dumps 
    payload = encoder(data) 
    File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/contextlib.py", line 77, in __exit__ 
    self.gen.throw(type, value, traceback) 
    File "/Users/kai/github-projects/Ticket-System/venv/lib/python3.5/site-packages/kombu/serialization.py", line 54, in _reraise_errors 
    reraise(wrapper, wrapper(exc), sys.exc_info()[2]) 
    File "/Users/kai/github-projects/Ticket-System/venv/lib/python3.5/site-packages/vine/five.py", line 175, in reraise 
    raise value.with_traceback(tb) 
    File "/Users/kai/github-projects/Ticket-System/venv/lib/python3.5/site-packages/kombu/serialization.py", line 50, in _reraise_errors 
    yield 
    File "/Users/kai/github-projects/Ticket-System/venv/lib/python3.5/site-packages/kombu/serialization.py", line 221, in dumps 
    payload = encoder(data) 
    File "/Users/kai/github-projects/Ticket-System/venv/lib/python3.5/site-packages/kombu/utils/json.py", line 72, in dumps 
    **dict(default_kwargs, **kwargs)) 
    File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/json/__init__.py", line 237, in dumps 
    **kw).encode(obj) 
    File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/json/encoder.py", line 198, in encode 
    chunks = self.iterencode(o, _one_shot=True) 
    File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/json/encoder.py", line 256, in iterencode 
    return _iterencode(o, 0) 
    File "/Users/kai/github-projects/Ticket-System/venv/lib/python3.5/site-packages/kombu/utils/json.py", line 62, in default 
    return super(JSONEncoder, self).default(o) 
    File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/json/encoder.py", line 179, in default 
    raise TypeError(repr(o) + " is not JSON serializable") 
kombu.exceptions.EncodeError: <Flask 'src'> is not JSON serializable 

用於發送電子郵件的代碼,是我notifications.py

notifications.py

import json 

from flask import render_template 
from flask_mail import Message 

from src import app 
from src.config import mail 

from celery import Celery 

with open('src/config_values.json') as f: 
    config_f = json.load(f) 

celery = Celery('tasks', broker='amqp://localhost//') 

@celery.task() 
def send_async_email(app, msg): 

    with app.app_context(): 
     mail.send(msg) 


def send_email(subject, sender, recipients, html_body): 

    msg = Message(subject, sender=sender, recipients=recipients) 
    msg.html = html_body 
    send_async_email.delay(app, msg) 


def email_notification(cust_name, cust_email, tix): 

    send_email("[Support Ticket #{tix}]!".format(tix=tix), 
       config_f['MAIL_USERNAME'], 
       [cust_email], 
       render_template("ticket_email.html", 
           c_name=cust_name, tix=tix)) 

要初始化電子郵件裏面,我用我的裏面的email_notification函數文件

views.py

from src.notifications import email_notification 

@app.route('/') 
def home(): 
    form = TicketForm() 

    if form.validate_on_submit() and request.method == 'POST': 

     # Handle form here .... 

     email_notification(cust_f_name, cust_email, tix_num) 

編輯:

這是我config.py文件用我所有的app配置和__init__.py文件是我 「創造」 的app

config.py

import json 
import os 
import sys 

from flask_admin import Admin 
from flask_bootstrap import Bootstrap 
from flask_mail import Mail 
from flask_socketio import SocketIO 
from flask_sqlalchemy import SQLAlchemy 

from src import app 

# JSON config file 
with open('src/config_values.json') as f: 
    config_f = json.load(f) 
def db_uri(system): 
    """ 
    Check system type for database URI setup 

    :param system: `sys.platform()` will be passed in 
    :return: system type 
    """ 
    # Mac 
    if system == 'darwin': 
     uri = 'sqlite:////' + os.getcwd() + '/ticket_system.sqlite' 
    # Windows 
    elif system == 'win32': 
     uri = r'sqlite:///' + os.getcwd() + '\ticket_system.sqlite' 
    # Linux 
    elif system == 'linux': 
     uri = 'sqlite:////' + os.getcwd() + '/ticket_system.sqlite' 
    # Linux2 
    elif system == 'linux2': 
     uri = 'sqlite:////' + os.getcwd() + '/ticket_system.sqlite' 
    # If system could not be determined 
    else: 
     raise FileNotFoundError('SQLite File was not able to be found') 
    # Return system type 
    return uri 


# All configuration needed for Flask 
app.secret_key = os.urandom(24) 
app.config['SQLALCHEMY_DATABASE_URI'] = db_uri(sys.platform) 
app.config['DATABASE_FILE'] = config_f['DATABASE_FILE'] 
app.config['SQLALCHEMY_ECHO'] = config_f['SQLALCHEMY_ECHO'] 
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = config_f['SQLALCHEMY_TRACK_MODIFICATIONS'] 
app.config['MAIL_SERVER'] = config_f['MAIL_SERVER'] 
app.config['MAIL_PORT'] = config_f['MAIL_PORT'] 
app.config['MAIL_USERNAME'] = config_f['MAIL_USERNAME'] 
app.config['MAIL_PASSWORD'] = config_f['MAIL_PASSWORD'] 
app.config['MAIL_USE_TLS'] = config_f['MAIL_USE_TLS'] 
app.config['MAIL_USE_SSL'] = config_f['MAIL_USE_SSL'] 
app.config['RECAPTCHA_PUBLIC_KEY'] = config_f['cap_pub'] 
app.config['RECAPTCHA_PRIVATE_KEY'] = config_f['cap_sec'] 

Bootstrap(app) 
db = SQLAlchemy(app) 
mail = Mail(app) 
admin = Admin(app, name='Tickets', template_mode='bootstrap3') 
socketio = SocketIO(app) 

__init__.py

from flask import Flask 

app = Flask(__name__) 
from src.views import app 

這是我的整個文件夾結構

Ticket-System\ 
    src\ 
     __init__.py 
     config.json 
     config_values.json 
     decorators.py 
     forms.py 
     models.py 
     notifications.py 
     views.py 
    venv\ 
    api_check.py 
    requirements.txt 
    run.py 
+0

能否請你包括你所在的文件的內容實例化你的'應用程序'? – errata

+0

@errata我對帖子進行了編輯 – kstullich

+0

在'__init __。py'(最後一行)中,來自src.views導入應用程序的目的是什麼? – errata

回答

5

當你與Celery異步執行一個任務,您將消息發送到代理。所以在這個引擎下有一個消息的序列化,這意味着你傳遞給這個任務的參數也是序列化的。由於Celery v4.0默認序列化程序是JSON。

在您的任務send_async_email中,您傳遞了一個參數app,這可能不是JSON序列化,這就是爲什麼您有錯誤。

在我看來,如果可以的話,最好避免將對象實例傳遞給任務。所以你的情況這裏是我會做什麼:

notifications.py

@celery.task() 
def email_notification(cust_name, cust_email, tix): 
    subject = "[Support Ticket #{tix}]!".format(tix=tix) 
    sender = config_f['MAIL_USERNAME'] 
    recipients = [cust_email] 
    html_body = render_template("ticket_email.html", c_name=cust_name, tix=tix) 

    msg = Message(subject, sender=sender, recipients=recipients) 
    msg.html = html_body 
    with app.app_context(): 
     mail.send(msg) 

views.py

from src.notifications import email_notification 
@app.route('/') 
def home(): 
    form = TicketForm() 

    if form.validate_on_submit() and request.method == 'POST': 

     # Handle form here .... 

     email_notification.delay(cust_f_name, cust_email, tix_num) 
+0

@peter謝謝你,當我刪除'app'參數時,我將得到以下錯誤:kombu.exceptions.EncodeError:不是JSON serializable'。我如何序列化'Flask-Mail'消息對象? – kstullich

+0

我不會序列化它。我會在任務中創建消息對象(請參閱我的編輯) – arthur

+0

完美運行,謝謝!但出於某種原因,我沒有在控制檯中爲我的'celery'任務獲取任何輸出。通過輸出,我的意思是這些任務已經完成。它雖然工作完全正常。 – kstullich