My goal is to get arbitrary code to run after my Flask application is started. Here is what I've got:
def run():
from webapp import app
app.run(debug=True, use_reloader=False)
Ideally I would be able to just do this:
def run():
from webapp import app
app.run(debug=True, use_reloader=False)
some_code()
But the code doesn't continue past app.run()
, so some_code() never runs.
The solution I'm working on at the moment is to run some_code() in a separate thread from app.run(), create a before first request function that sets this:
app.is_running = True
Then get some_code() to shoot a basic request to app so that the 'before first request' code runs. This is fairly convoluted and going to be hard to document. I would rather use app.is_running parameter which already is provided in Flask, or use a @app.after_server_start
decorator, but to my knowledge neither of those exists.
Help me make this code better?
Posthumous: Every time I think about this issue, it makes me wish that a @app.after_server_start
decorator existed.
Use Flask-Script to run your app, then overwrite the runserver class/method like this
If you need to execute some code after your flask application is started but strictly before the first request, not even be triggered by the execution of the first request as @app.before_first_request can handle, you should use Flask_Script, as CESCO said, but you could subclass the class Server and overwrite the __ call __ method, instead of overwriting the runserver command with @manager.command:
This way you don't override default options of runserver command.
I encountered this same issue in a flask app of mine. I wanted to start a scheduler at app startup, which would kick off some jobs at regular intervals. Since I deploy my apps inside docker containers, what I ended up doing is adding an "health check" endpoint which just returns a 200, and in my dockerfile configured that endpoint:
HEALTHCHECK CMD curl --fail http://localhost:8080/alive || exit 1
The default behavior is to execute that command every 30s, and the first run conveniently kicks off my init() method. https://docs.docker.com/engine/reference/builder/#healthcheck
I don't really like any of the methods mentioned above, for the fact that you don't need Flask-Script to do this, and not all projects are going to use Flask-Script already.
The easiest method, would be to build your own Flask sub-class. Where you construct your app with
Flask(__name__)
, you would simply add your own class and use it instead.Of course, this doesn't run after it starts, but right before
run()
is finally called. With app context, you should be able to do anything you may need to do with the database or anything else requiring app context. This should work with any server (uwsgi, gunicorn, etc.) as well.If you need the
do_something()
to be non-blocking, you can simply thread it withthreading.Thread(target=do_something).start()
instead.The conditional statement is to prevent the double call when using debug mode/reloader.
I just did (in a
main.py
executed withpython main.py
):This worked for me without the more comprehensive answers offered above. In my case
some_code()
is initializing a cache viaflask_caching.Cache
.But it probably depends on what exactly
some_code
is doing...