2015-09-30 7 views
5

Sto utilizzando Miguel Grinberg's article per configurare Celery con il pattern di fabbrica dell'app per inviare email con Flask-Mail. Ho chiamato vari script che usano Celery senza problemi. Tuttavia continuo a ricevere Runtime Error: working outside of application context con la seguente attività anche se sto eseguendo il worker all'interno di un contesto dell'app. Perché ricevo questo errore? Come faccio a far funzionare Flask-Mail in Celery?L'esecuzione di worker di Celery all'interno di un contesto app genera ancora un errore "working outside of app app" nell'attività

email.py:

from flask import current_app, render_template 
from flask.ext.mail import Message 
from . import celery, mail 

@celery.task 
def send_async_email(msg): 
    mail.send(msg) 

def send_email(to, subject, template, **kwargs): 
    with current_app.test_request_context(): # used app_context() as well. 
     msg = Message(current_app.config['PORTAL_MAIL_SUBJECT_PREFIX'] + ' ' +          subject, 
        sender=current_app.config['PORTAL_MAIL_SENDER'], recipients=[to]) 
     msg.body = render_template(template + '.txt', **kwargs) 
     msg.html = render_template(template + '.html', **kwargs) 
     send_async_email.delay(msg) 

__init__.py:

from flask import Flask 
from celery import Celery 
from flask.ext.mail import Mail 
from configuration import config 

mail = Mail() 
celery = Celery(__name__, broker=config['default'].CELERY_BROKER_URL) 

def create_app(config_name): 
    app = Flask(__name__) 
    app.config.from_object(config[config_name]) 
    config[config_name].init_app(app) 
    mail.init_app(app) 
    celery.conf.update(app.config) 
    app.register_blueprint(main_blueprint) 
    return app 

celery_worker.py:

import os 
from app import celery, create_app 

app = create_app(os.getenv('FLASK_CONFIG') or 'default') 
app.app_context().push() 

Errore:

C:\Python27\Scripts\celery.exe worker -A celery_worker.celery --loglevel=info 

[2015-09-30 12:07:34,408: INFO/MainProcess] Received task: app.email.send_async_email[3ec772ff-4767-49cb-90ba-445629da30da] 
[2015-09-30 12:07:34,417: ERROR/MainProcess] Task app.email.send_async_email[3ec772ff-4767-49cb-90ba-445629da30da] raised unexpected: RuntimeError('working outside of application context',) 
Traceback (most recent call last): 
    File "C:\Python27\lib\site-packages\celery\app\trace.py", line 240, in trace_task 
    R = retval = fun(*args, **kwargs) 
    File "C:\Python27\lib\site-packages\celery\app\trace.py", line 438, in __protected_call__ 
    return self.run(*args, **kwargs) 
    File "<flask_project_path>\app\email.py", line 10, in send_async_email 
    mail.send(msg) 
    File "C:\Python27\lib\site-packages\flask_mail.py", line 491, in send 
    with self.connect() as connection: 
    File "C:\Python27\lib\site-packages\flask_mail.py", line 508, in connect 
    return Connection(app.extensions['mail']) 
    File "C:\Python27\lib\site-packages\werkzeug\local.py", line 338, in __getattr__ 
    return getattr(self._get_current_object(), name) 
    File "C:\Python27\lib\site-packages\werkzeug\local.py", line 297, in _get_current_object 
    return self.__local() 
    File "C:\Python27\lib\site-packages\flask\globals.py", line 34, in _find_app 
    raise RuntimeError('working outside of application context') 
RuntimeError: working outside of application context 

ho provato:

  • Cercando di passare il contesto di applicazione al metodo send_email.
  • Spostamento del metodo send_async_email in un modulo tasks.py in cui risiedono il resto dei compiti di sedano.
  • Rendering dei modelli al di fuori dei metodi di posta elettronica e passarli come argomenti.

risposta

1

sono stato in grado di risolvere il problema con la creazione di un'istanza dell'applicazione pallone a livello locale:

email.py:

from flask import render_template, current_app 
from flask.ext.mail import Message 
from . import celery, mail, create_app 


@celery.task 
def send_async_email(msg): 
    app = create_app('default' or 'development') # -> fixed 
    with app.app_context(): 
     mail.send(msg) 


def send_email(to, subject, template, **kwargs): 
    app = current_app._get_current_object() 
    msg = Message(current_app.config['PORTAL_MAIL_SUBJECT_PREFIX'] + ' ' +  subject, 
    sender=current_app.config['MAIL_USERNAME'], recipients=[to]) 
    msg.body = render_template(template + '.txt', **kwargs) 
    msg.html = render_template(template + '.html', **kwargs) 
    send_async_email.delay(msg)