Skip to content

Instantly share code, notes, and snippets.

@nguyenkims
Created July 11, 2017 08:56
Show Gist options
  • Star 16 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save nguyenkims/ff0c0c52b6a15ddd16832c562f2cae1d to your computer and use it in GitHub Desktop.
Save nguyenkims/ff0c0c52b6a15ddd16832c562f2cae1d to your computer and use it in GitHub Desktop.
An example on how to reload Flask app in runtime
"""
This is an example on how to reload Flask app in runtime
It can be useful for the use case where you want to enable/disable blueprints/routes dynamically.
To run the app:
> pip install flask & python app.py
Then test it via curl
> curl localhost:5000/
> curl localhost:5000/reload
> curl localhost:5000/ # should see a different start time as the flask app is replaced
"""
from datetime import datetime
from flask import Flask
from werkzeug.serving import run_simple
# set to True to inform that the app needs to be re-created
to_reload = False
def get_app():
print("create app now")
app = Flask(__name__)
# to make sure of the new app instance
now = datetime.now()
@app.route("/")
def index():
return f"hello, the app started at %s" % now
@app.route('/reload')
def reload():
global to_reload
to_reload = True
return "reloaded"
return app
class AppReloader(object):
def __init__(self, create_app):
self.create_app = create_app
self.app = create_app()
def get_application(self):
global to_reload
if to_reload:
self.app = self.create_app()
to_reload = False
return self.app
def __call__(self, environ, start_response):
app = self.get_application()
return app(environ, start_response)
# This application object can be used in any WSGI server
# for example in gunicorn, you can run "gunicorn app"
application = AppReloader(get_app)
if __name__ == '__main__':
run_simple('localhost', 5000, application,
use_reloader=True, use_debugger=True, use_evalex=True)
@Yakuza-UA
Copy link

Nice one. One question. What if all my app routes are in a separate module?

I tried to add from app import routes to get_app() function, but because within that module I refer to application variable, it complains that variable is not yet initialized. So, it's chicken and the egg situation. I cannot import code into get_app() because at runtime application is not yet initialized.

I didn't want to encapsulate all my route decorators into get_app function as it is going to be HUGE... but there's no other choice as it seems.

@nguyenkims
Copy link
Author

@yaku: sorry about the late reply!

Nice one. One question. What if all my app routes are in a separate module?

The "trick" in the script is to use to_reload as a flag. If the app route is in a different module, you can create a new module, let's say config.py that contains this to_reload flag, this module can then be imported by both the endpoint and the module that contains AppReloader class.

I tried to add from app import routes to get_app() function, but because within that module I refer to application variable, it complains that variable is not yet initialized. So, it's chicken and the egg situation. I cannot import code into get_app() because at runtime application is not yet initialized.

The get_app function follows the app factory pattern. In this pattern, to declare routes, we don't import app directly but either use blueprint (and then add these blueprint later in get_app) or do something like this:

def declare_routes(app):
    @app.route("/route_1")
    def route_1():
          ....

## in get_app
from route import declare_routes
def get_app():
    # init app ...
    declare_routes(app)

I didn't want to encapsulate all my route decorators into get_app function as it is going to be HUGE... but there's no other choice as it seems.

In this case you can use the "blueprint" pattern https://flask.palletsprojects.com/en/1.1.x/blueprints/ to group related endpoints.

@evandrocoan
Copy link

This does not "reload Flask app in runtime". This only recreates the Flask application object when accessing some route.

With reloading, it was supposed to mean all Python source code file changes are reloaded. But this is only performed by the use_reloader=True parameter of run_simple.

@nguyenkims
Copy link
Author

@evandrocoan thanks for the precision! The wording reload is indeed misleading. The usecase for this snippet is more about enable/disable some routes dynamically, via the input to the /reload route.

@Akonibrahim
Copy link

When flask debug is turned on it reloads the whole code without killing and restarting server anyone has any idea on triggering that functionality from code without debug mode

@darryllane
Copy link

darryllane commented Apr 17, 2020

Im keen to find a way to reload config and the app. Im looking to take DB settings from a form and load them into the application to use.

@neveragain2003
Copy link

neveragain2003 commented Apr 29, 2020

Im keen to find a way to reload config and the app. Im looking to take DB settings from a form and load them into the application to use.
@darryllane
Same here. I got the values loaded from the database, my problem is getting the new settings to take when they are changed without manually reloading the application.

EDIT: What I ended up doing was creating a file in the root folder, opening the file and re-writing what was already in there to it. I'm using Gunicorn and added the --reload-extra-file command to monitor that file for changes. After I make my settings changes in the database, I change the file which causes a reload of the app. Probably not the most elegant or proper solution, but it works.

@Akonibrahim
Copy link

Akonibrahim commented May 5, 2020

Im keen to find a way to reload config and the app. Im looking to take DB settings from a form and load them into the application to use.
@darryllane
Same here. I got the values loaded from the database, my problem is getting the new settings to take when they are changed without manually reloading the application.

EDIT: What I ended up doing was creating a file in the root folder, opening the file and re-writing what was already in there to it. I'm using Gunicorn and added the --reload-extra-file command to monitor that file for changes. After I make my settings changes in the database, I change the file which causes a reload of the app. Probably not the most elegant or proper solution, but it works.

I did a similar thing with gunicorn.
When I run gunicorn I run it like this gunicorn -b 0.0.0.0:8000 -p app.pid run:app so I get the PID number in a file. To restart it I'm sending HUP signal that restarts the server by checking all the workers finished their tasks.
`
import os
from app import create_app
app = create_app()
class CommandRunner():

@staticmethod
def restart_server():
    path = os.path.join(app.root_path,"..","app.pid")
    if os.path.exists(path):
        with open(path,"r+") as file:
            pid = file.read()
        cmd = "kill -s HUP "+pid
        os.system(cmd)

`
Which is also not a proper one. Please keep this thread updated if you guys find any other elegant solution.

@mrkprdo
Copy link

mrkprdo commented Aug 15, 2020

I was looking some ways to do an actual reload, and as of this writing, i thought, why not run the entire flask app from a subprocess perspective, then kill it and call the subprocess again to start the server again. The key here is to save the PID of the process into a file, and use it to get the PID and execute os.kill from flask's route

lets say main.py

def start():
    process = Popen(['python','run.py'],shell=True)
    with open('PID.file','w+') as pidfile:
        pidfile.write(process.pid)

& app.py

@app.route('reload')
def reload():
    with open('PID;file','r') as pidfile:
        pid = pidfile.read()
    os.kill(pid,, signal.SIGKILL)
    main.start()

@hyperking
Copy link

hyperking commented May 15, 2021

I ran into a similar issue where I needed to reload a Flask site theme configuration.
I simply created a method that imported the current Flask application and then manually updated certain configurations.
I later executed the reload method within a Flask controller method.

In my use case, I needed to update the template and assets path but you could add whatever needs to be updated.

def reload():
    from flask import current_application
    current_application.template_folder = "new/path/to/templates"
    current_application.static_folder = "new/path/to/static/folder"
    # Add whatever configuration that needs to be updated

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment