我正在尝试使用Celery和RabbitMQ异步发送电子邮件。这是我第一次使用Celery,所以我不太熟悉一些错误。我意识到回溯来自一个名为kombu
的包,我知道它是Celery的依赖。我只是无法调试它。
每当我测试发送电子邮件时都会发生回溯。
回溯:
[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
功能
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
文件,我{创建'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)
:
config.py
from flask import Flask
app = Flask(__name__)
from src.views import app
__初始化__。PY
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
这是我的整个文件夹结构
def index
@posts = current_author.posts.most_recent
end
def show
end
def new
@post = current_author.posts.new
end
private
def set_post
@post = current_author.posts.friendly.find(params[:id])
end
def post_params
params.require(:post).permit(:title, :body, :description, :banner_image_url, :tag_list)
end
end
end
答案 0 :(得分:13)
当您与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)