Колба Python с сельдереем из контекста приложения

Я создаю сайт, используя флэшку python. Все идет хорошо, и теперь я пытаюсь внедрить сельдерей.

Это шло хорошо, пока я не попытался отправить электронное письмо с использованием фляжки из сельдерея. Теперь я получаю сообщение об ошибке "Работа вне контекста приложения".

полная трассировка

  Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/celery/task/trace.py", line 228, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/usr/lib/python2.7/site-packages/celery/task/trace.py", line 415, in __protected_call__
    return self.run(*args, **kwargs)
  File "/home/ryan/www/CG-Website/src/util/mail.py", line 28, in send_forgot_email
    msg = Message("Recover your Crusade Gaming Account")
  File "/usr/lib/python2.7/site-packages/flask_mail.py", line 178, in __init__
    sender = current_app.config.get("DEFAULT_MAIL_SENDER")
  File "/usr/lib/python2.7/site-packages/werkzeug/local.py", line 336, in __getattr__
    return getattr(self._get_current_object(), name)
  File "/usr/lib/python2.7/site-packages/werkzeug/local.py", line 295, in _get_current_object
    return self.__local()
  File "/usr/lib/python2.7/site-packages/flask/globals.py", line 26, in _find_app
    raise RuntimeError('working outside of application context')
RuntimeError: working outside of application context

Это моя почтовая функция:

@celery.task
def send_forgot_email(email, ref):
    global mail
    msg = Message("Recover your Crusade Gaming Account")
    msg.recipients = [email]
    msg.sender = "Crusade Gaming [email protected]"
    msg.html = \
        """
        Hello Person,<br/>

        You have requested your password be reset. <a href="{0}" >Click here recover your account</a> or copy and paste this link in to your browser: {0} <br />

        If you did not request that your password be reset, please ignore this.
        """.format(url_for('account.forgot', ref=ref, _external=True))
    mail.send(msg)

Это мой файл сельдерея:

from __future__ import absolute_import

from celery import Celery

celery = Celery('src.tasks',
                broker='amqp://',
                include=['src.util.mail'])


if __name__ == "__main__":
    celery.start()

Ответ 1

Для флеш-почты для корректной работы контекста приложения флажок. Создайте экземпляр объекта приложения со стороны сельдерея и используйте app.app_context следующим образом:

with app.app_context():
    celery.start()

Ответ 2

В вашем файле mail.py импортируйте объекты "приложение" и "почта". Затем используйте контекст запроса. Сделайте что-то вроде этого:

from whateverpackagename import app
from whateverpackagename import mail

@celery.task
def send_forgot_email(email, ref):
    with app.test_request_context():
        msg = Message("Recover your Crusade Gaming Account")
        msg.recipients = [email]
        msg.sender = "Crusade Gaming [email protected]"
        msg.html = \
        """
        Hello Person,<br/>
        You have requested your password be reset. <a href="{0}" >Click here recover your account</a> or copy and paste this link in to your browser: {0} <br />
        If you did not request that your password be reset, please ignore this.
        """.format(url_for('account.forgot', ref=ref, _external=True))

        mail.send(msg)

Ответ 3

У меня нет никаких точек, поэтому я не смог бы перевернуть @codegeek выше ответа, поэтому решил написать свой собственный, так как поиску такой проблемы помог этот вопрос/ответ: у меня только что было некоторые успехи пытаются решить аналогичную проблему в сценарии python/flask/celery. Несмотря на то, что ваша ошибка заключалась в попытке использовать mail, в то время как моя ошибка заключалась в попытке использовать url_for в задаче на сельдерей, я подозреваю, что эти два были связаны с одной и той же проблемой и что у вас были бы ошибки, связанные с использованием url_for, если вы пытались использовать это до mail.

Без контекста приложения, присутствующего в задаче celery (даже после включения import app from my_app_module), я тоже получал ошибки. Вам нужно выполнить операцию mail в контексте приложения:

from module_containing_my_app_and_mail import app, mail    # Flask app, Flask mail
from flask.ext.mail import Message    # Message class

@celery.task
def send_forgot_email(email, ref):
    with app.app_context():    # This is the important bit!
        msg = Message("Recover your Crusade Gaming Account")
        msg.recipients = [email]
        msg.sender = "Crusade Gaming [email protected]"
        msg.html = \
        """
        Hello Person,<br/>
        You have requested your password be reset. <a href="{0}" >Click here recover your account</a> or copy and paste this link in to your browser: {0} <br />
        If you did not request that your password be reset, please ignore this.
        """.format(url_for('account.forgot', ref=ref, _external=True))

        mail.send(msg)

Если кому-то интересно, мое решение проблемы использования url_for в задачах сельдерея можно найти здесь