Flask-Mail разбивает сельдерей

У меня есть приложение Flask, в котором отлично работает сельдерей и Flask-Mail.

from celery import Celery
from flask_mail import Mail, Message
app = Flask(__name__)
mail = Mail(app)

celery = Celery('main_app', 
                 broker='mongodb://localhost',
                 backend='mongodb://localhost')
@celery.task
def cel_test():
     return 'cel_test'

@app.route('/works_maybe')
def works_maybe():
    return cel_test.delay()

ВСЕ ИДЕТ НОРМАЛЬНО

cel_test отлично работает с работником сельдерея; все проявляется в монго.

Но вот где это становится странным. Метод подписки плюс почта работает на 100% без @celery.task, но взрывается, когда это становится задачей.

@celery.task
def send_email(some_arg, name, email):
    msg = Message(…message details..)
    return mail.send(msg)

@app.route("/signup", methods=['POST'])
def signup():
    return send_email.delay(...stuff for the message…)

ТРАССА

R = retval = fun(*args, **kwargs)
File "/Users/username/pymods/virtualenvs/directory/lib/python2.7/site-packages/celery-3.0.15-py2.7.egg/celery/task/trace.py", line 415, in __protected_call__
return self.run(*args, **kwargs)
File "/Users/username/pymods/directory/directory/main_app/main_app.py", line 43, in send_email
something = 'a string in the Message'),
File "/Users/username/pymods/virtualenvs/directory/lib/python2.7/site-packages/flask/templating.py", line 123, in render_template
ctx.app.update_template_context(context)  
AttributeError: 'NoneType' object has no attribute 'app'

Может кто-нибудь объяснить, почему в одном случае сельдерей работает отлично, но когда я использую mail.send (msg), он ломается?

Может быть, есть что-то, что мне нужно узнать с Python в целом?

Любые мысли, по крайней мере, как подход к этому типу вопроса будет принята с благодарностью.

1 ответ

Многое, что делается во флаке, связано с контекстом приложения. Например, render_template функция, он должен знать, где ваше приложение хранит свои шаблоны. session переменная хочет знать хранилище данных вашего приложения или систему кеширования. request объект, и ваш mail.send требовать некоторый контекст приложения при вызове.

Если вы хотите вызывать их вне области применения вашего фляги, как в вашей задаче celery, сделайте это в контексте приложения следующим образом:

...

with app.app_context():

    do_some_context_bound_actions()

    msg = Messgae(...)
    user_name = app.session["user"].name
    msg.html = render_template("mail/welcome.html", name=user_name)
    mail.send(msg)

...

Обновить

Ошибка находится в части render_template send_email задача.

@celery.task
def send_email(some_arg, name, email):
    msg = Message(
                  subject='hello', 
                  body=render_template('email.txt',
                  name=name, 
                  some_arg=some_arg),
                  recipients=[email]
                 )
    return mail.send(msg)

Когда я удаляю body=render_templateКаблаам, это работает.

у меня есть from flask import render_template, возможно render_template не может так работать?

Странно, без сельдерея send_email плюс render_template работает отлично.

Хакиш Успех

Когда я заставляю app_context с другой функцией все работает:

def create_email(some_arg, name, email):
    with app.test_request_context('/send_email'):
        return render_template('email.txt', 
                                name=name, 
                                some_arg=some_arg) 

а затем бросить его в send_email задача так

body = render_template('email.txt'…

становится

body= create_email(some_arg, name)

И мы дома свободны.

Другие вопросы по тегам