flask-executor
flask-executor copied to clipboard
Use with flask Blueprint
Can this module be used with flask Blueprint
s, and if so what would be an example usage?
You can't do executor = Executor(my_app_blueprint)
as that causes the following error:
AttributeError: 'Blueprint' object has no attribute 'config'
And you can't access flask.current_app
in the global scope. At the moment I'm creating the executor
inside of a flask route function if it's not been created already, but this isn't an ideal solution.
Any advice?
I have the same question.
I founded this workaround. Hope helps.
app.py
from flask import Flask
from . import my_blueprint
def create_app(test_config=None):
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
EXECUTOR_TYPE="process",
EXECUTOR_MAX_WORKERS="1",
)
my_blueprint.executor.init_app(app)
app.register_blueprint(blueprint.bp)
return app
my_blueprint.py
from flask import Blueprint, request
from flask_executor import Executor
executor = Executor()
bp = Blueprint("my_blueprint", __name__)
def long_runnung_function(data):
sleep(15)
return data
def done(fn):
if fn.cancelled():
print("canceled")
elif fn.done():
error = fn.exception()
if error:
print("error returned: {}".format(
error))
else:
result = fn.result()
print("value returned: {}".format(
result))
@bp.route("/data", methods=["POST"])
def data_upload():
"""data upload endpoint. Long running task."""
# do something with request
# THIS HANDLER NOT BLOCKS
future_response = executor.submit(long_runnung_function, request.data)
future_response.add_done_callback(done)
return {"upload started": 200}
@Oscar-Campo How is that workaround different from using ThreadPoolExecutor
(https://docs.python.org/3/library/concurrent.futures.html) directly? Where's the benefit from Flask-Executor now?
I'm new to Flask and just stumbled over the blueprint issue.
@svdHero The main benefit of using Flask-Executor in your flask app instead of the inbuilt executor is that it provides a FutureCollection
so u can access future objects at a later time or from some other section of your code.
This looks like it only works when you use functions that do not require the application context. So if your long running function wanted to make a call to the DB using SqlAlchemy for example I think it falls over with a no application context errror?
Here's something that works with the application context using the following principle, tested and working using uwsgi + nginx
executor.py
from flask_executor import Executor
executor = Executor()
my_blueprint.py
from flask import Blueprint
from executor import executor
my_bp = Blueprint()
app.py
from flask import Flask
from executor import executor
from my_blueprint import my_bp
app = Flask()
executor.init_app(app)
app.register_blueprint(my_bp)
I believe some of the underlying lib changes in the intervening years should solve for everything here, tasks are run under a new application context which have a copy of g
from the last request. Closing this, but feel free to open if you can reproduce any unexpected behaviour