How to excecute code after Flask `app.run()` statement (run a Flask app and a function in parallel, execute code while Flask server is running)

Question:

Recently added Flask to a sample infinite-loop which randomly prints words. However, when adding app.run(host='0.0.0.0') the code after that line won’t execute after I stop Flask running.

if __name__ == '__main__':
    app.run(host='0.0.0.0')

    while True:  # won't run until I press stop once (stop Flask) when running directly from IDE
        ...

What I want is to be able to run the while loop while the Flask app is running.

Is there any way to solve this?

Asked By: czr_RR

||

Answers:

Update 2023

To run some code before starting a Flask server, it is now recommended to use the Application Factory Pattern.

Basically, the idea is replacing app = Flask(__name__) with a proper function which returns the app object. For example, we can have something like this in our __init__.py:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_redis import FlaskRedis


# Globally accessible libraries
db = SQLAlchemy()
r = FlaskRedis()


def init_app():
    """Initialize the core application."""
    app = Flask(__name__, instance_relative_config=False)
    app.config.from_object('config.Config')

    # Initialize Plugins
    db.init_app(app)
    r.init_app(app)

    with app.app_context():
        # before_first_request equivalent here

        # Include our Routes
        from . import routes

        # Register Blueprints
        app.register_blueprint(auth.auth_bp)
        app.register_blueprint(admin.admin_bp)

        return app

So, for whatever was put under before_first_request before, just put them now under the with app.app_context():.

Then, in the application entrance (e.g. main.py), we simply use it:

app = init_app()

if __name__ == "__main__":
    app.run(host='0.0.0.0')

For more information, this nice article is recommended.


Deprecated since Flask 2.2

You can use before_first_request instead. Functions decorated with @app.before_first_request will run once before the first request to this instance of the application.

The code looks like this:

from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    print("index is running!")
    return "Hello world"

@app.before_first_request
def before_first_request_func():
    print("This function will run once")


if __name__ == "__main__":
    app.run(host="0.0.0.0")

The code in before_first_request_func will be executed once before the first request to the server. Therefore, after starting the Flask instance, one can simulate the first request to the server using curl or so.

Answered By: Triet Doan

You can do what you want by using multithreading:

from flask import Flask
import threading
import time

app = Flask(__name__)

@app.route("/")
def hello_world():
    return "Hello, World!"

def run_app():
    app.run(debug=False, threaded=True)

def while_function():
    i = 0
    while i < 20:
        time.sleep(1)
        print(i)
        i += 1

if __name__ == "__main__":
    first_thread = threading.Thread(target=run_app)
    second_thread = threading.Thread(target=while_function)
    first_thread.start()
    second_thread.start()

Output:

 * Serving Flask app "app"
 * Environment: production
 * Debug mode: off
 * Running on [...] (Press CTRL+C to quit)
0
1
2
3
4
5
6
7
8
[...]

The idea is simple:

  • create 2 functions, one to run the app and an other to execute the wile loop,
  • and then execute each function in a seperate thread, making them run in parallel

You can do this with multiprocessing instead of multithreading too:

The (main) differences here is that the functions will run on different CPUs and in memory spaces.

from flask import Flask
from multiprocessing import Process
import time

# Helper function to easly  parallelize multiple functions
def parallelize_functions(*functions):
    processes = []
    for function in functions:
        p = Process(target=function)
        p.start()
        processes.append(p)
    for p in processes:
        p.join()

# The function that will run in parallel with the Flask app
def while_function():
    i = 0
    while i < 20:
        time.sleep(1)
        print(i)
        i += 1

app = Flask(__name__)

@app.route("/")
def hello_world():
    return "Hello, World!"

def run_app():
    app.run(debug=False)

if __name__ == '__main__':
    parallelize_functions(while_function, run_app)

If you want to use before_first_request proposed by @Triet Doan: you will have to pass the while function as an argument of before_first_request like this:

from flask import Flask
import time

app = Flask(__name__)

def while_function(arg):
    i = 0
    while i < 5:
        time.sleep(1)
        print(i)
        i += 1

@app.before_first_request(while_function)
@app.route("/")
def index():
    print("index is running!")
    return "Hello world"

if __name__ == "__main__":
    app.run()

In this setup, the while function will be executed, and, when it will be finished, your app will run, but I don’t think that was what you were asking for?

Answered By: Rivers
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.