Reputation: 591
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?
Upvotes: 5
Views: 11433
Reputation: 12083
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.
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.
Upvotes: 9
Reputation: 1923
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:
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?
Upvotes: 6