I have a Flask Application with an MVC structure:
my_app
├── server.py
├── requirements.txt
├── models
│ ├── __init__.py
└── model.py
├── controllers
├── __init__.py
├── client_controllers
└──controller.py
└── another_controller.py
└── templates
I use blueprints to split the server code in “controllers” so I have something like this:
server.py:
from flask import Flask
from celery import Celery
from controllers.client_controllers.controller import controller
app = Flask(__name__)
app.secret_key = 'SECRET'
app.register_blueprint(controller)
# Celery Configuration
def make_celery(app):
celery = Celery(app.import_name, backend=app.config['CELERY_RESULT_BACKEND'],
broker=app.config['CELERY_BROKER_URL'])
celery.conf.update(app.config)
TaskBase = celery.Task
class ContextTask(TaskBase):
abstract = True
def __call__(self, *args, **kwargs):
with app.app_context():
return TaskBase.__call__(self, *args, **kwargs)
celery.Task = ContextTask
return celery
app.config.update(
CELERY_BROKER_URL='redis://localhost:6379',
CELERY_RESULT_BACKEND='redis://localhost:6379'
)
celery = make_celery(app)
if __name__ == "__main__":
app.run(host='0.0.0.0', debug=True)
controller.py:
from flask import Blueprint, render_template, json, request, redirect, url_for, abort, session
controller = Blueprint('controller', __name__,
template_folder='templates/')
@celery.task()
def add_together(a, b):
return a + b
@controller.route('/add', methods=['GET'])
def add():
result = add_together.delay(23, 42)
result.wait()
return 'Processing'
As you may notice, celery is not imported into the controller, because I don’t know how to import the celery instance from server.py into my controller.py without getting an error, I’ve been trying with:
from ...server import celery
from ..server import celery
...etc
but still failing with errors.
2
Answers
One option is to assign celery instance to the app instance and then access it through flask’s
current_app
.In you server.py, just add:
Then you can access this in your controller.py:
The flask Error
RuntimeError: Working outside of application context.
happens because you are not in a Flask application_context().You should use celery shared_task which is what you need given your MVC structure.
Script app_tasks.py
The @shared_task decorator returns a proxy that always points to the active Celery instances:
After you define you task you can call them using a reference to a Celery app. This celery app could be part of the flask application_context(). Example:
Script server.py
Script some_controller.py
Finally, start the worker to consume the tasks:
Script celery_worker.py