Starting a celery worker inside an application context still causes a "work out of application context" error in the task

I am using Miguel Greenberg's article to install celery with a factory application template for sending emails using Flask-Mail. I call various scripts that use Celery without any problems. However, I keep getting Runtime Error: working outside of application context with the following task, even if I run the worker inside the application context. Why am I getting this error? How to get Flask-Mail to work in Celery?

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() 

Error:

 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 

I tried:

  • An attempt to pass the application context to the send_email method.
  • Moving the send_async_email method to the tasks.py module, where the other tasks related to celery are located.
  • Rendering templates outside email methods and passing them as arguments.
+5
source share
2 answers

I managed to fix this problem by creating an instance of the jar application locally:

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) 
+2
source

As @ Alan stuart noted, the problem was resolved by creating a jar application instance locally.

But let's say if there are 10 or 15 different tasks in the file ... we need to create 10 or 15 different instances of the application locally, which looks pretty AWESOME :).

What is the best way to handle this ...? I really appreciate for any feedback!

-1
source

Source: https://habr.com/ru/post/1232632/


All Articles