flask-executor icon indicating copy to clipboard operation
flask-executor copied to clipboard

Use with flask Blueprint

Open davidferguson opened this issue 5 years ago • 6 comments

Can this module be used with flask Blueprints, 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?

davidferguson avatar Nov 02 '19 21:11 davidferguson

I have the same question.

jbarnett1981 avatar Jan 15 '20 15:01 jbarnett1981

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 avatar Mar 15 '20 15:03 Oscar-Campo

@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 avatar Dec 04 '20 14:12 svdHero

@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.

eshaan7 avatar Dec 04 '20 14:12 eshaan7

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?

samredway avatar Dec 08 '20 14:12 samredway

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)

JerryLui avatar Feb 16 '21 08:02 JerryLui

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

dchevell avatar Aug 19 '22 10:08 dchevell