kombu.exceptions.EncodeError: <Flask 'src'> is not JSON serializable
celery, flask, python
Solution
When you execute a task asynchronously with `Celery`, you send a message to the broker. So under the hood there is a serialization of the message, this means the arguments you pass to the task are also serialized. Since `Celery v4.0` the default serializer is JSON.
In your task `send_async_email` you pass an argument `app` which is probably not JSON serializable that's why you have an error.
In my opinion, it's better to avoid to pass object instances to task if you can. So in your case here is what I would do :
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)
Problem
I am trying to send emails asynchronously using Celery and RabbitMQ. This is the first time I am ever using Celery so I am not very familiar with some of the errors. I realize the traceback is coming from a package called `kombu` which I know is a dependency for Celery. I am just not able to debug this. The traceback happens whenever I test out trying to send an email. Traceback: ``` [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 ``` The code for sending the email, is inside of my `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)) ``` To initialize the email, I use the `email_notification` function inside of my `views.py` file 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) ``` EDIT: This is my `config.py` file with all my `app` configurations and the `__init__.py` file is where I "create" the `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 ``` This is my entire folder structure ``` 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 ```