85

I'm currently developing a Python application on which I want to see real-time statistics. I wanted to use Flask in order to make it easy to use and to understand.

The issue is that my Flask server should start at the very beginning of my Python application and stop at the very end. It should look like this:

def main():
    """ My main application """
    from watcher.flask import app
    # watcher.flask define an app as in the Quickstart flask documentation.
    # See: http://flask.pocoo.org/docs/0.10/quickstart/#quickstart

    app.run() # Starting the flask application

    do_my_stuff()

    app.stop() # Undefined, for the idea 

Because I need my application context (for the statistics), I can't use a multiprocessing.Process. Then I was trying to use a threading.Thread, but it looks like Werkzeug doesn't like it:

 * Running on http://0.0.0.0:10079/
Exception in thread Flask Server:
Traceback (most recent call last):
  File "/usr/lib/python2.7/threading.py", line 810, in __bootstrap_inner
    self.run()
  File "/usr/lib/python2.7/threading.py", line 763, in run
    self.__target(*self.__args, **self.__kwargs)
  File ".../develop-eggs/watcher.flask/src/watcher/flask/__init__.py", line 14, in _run
    app.run(host=HOSTNAME, port=PORT, debug=DEBUG)
  File ".../eggs/Flask-0.10.1-py2.7.egg/flask/app.py", line 772, in run
    run_simple(host, port, self, **options)
  File ".../eggs/Werkzeug-0.7-py2.7.egg/werkzeug/serving.py", line 609, in run_simple
    run_with_reloader(inner, extra_files, reloader_interval)
  File ".../eggs/Werkzeug-0.7-py2.7.egg/werkzeug/serving.py", line 524, in run_with_reloader
    signal.signal(signal.SIGTERM, lambda *args: sys.exit(0))
ValueError: signal only works in main thread

How can I do that without running Flask in the main thread?

ballade4op52
  • 2,142
  • 5
  • 27
  • 42
FunkySayu
  • 7,641
  • 10
  • 38
  • 61
  • I've ran Flask apps in a separate thread, so this error you're seeing is surprising. Do you have the full traceback? – Thomas Orozco Jul 07 '15 at 09:42
  • Full traceback added – FunkySayu Jul 07 '15 at 09:49
  • Did you somehow set `app.debug = True`? – Thomas Orozco Jul 07 '15 at 10:01
  • Yes I did. It can't be set to True if i'm threading ? – FunkySayu Jul 07 '15 at 10:03
  • Can you show the code where you ran flask in a separate thread? – Jwan622 Aug 02 '19 at 17:01
  • Generally, it is not a good idea to run server on separate "thread", what you need to do is to run server on separate "process". Because OS usually schedules the threads in round-robin fashion. Meaning that, main thread and child thread of process are usually swapped in and swapped out, meaning that, when your thread on which server is running is swapped out then server will not be able to process any request as it is down. On the other hand, if your server is running on a "process" using multi-processing then server will always be online because processes are not swapped in and out. – Syed Shaharyaar Hussain Mar 31 '22 at 11:14

5 Answers5

100

You're running Flask in debug mode, which enables the reloader (reloads the Flask server when your code changes).

Flask can run just fine in a separate thread, but the reloader expects to run in the main thread.


To solve your issue, you should either disable debug (app.debug = False), or disable the reloader (app.use_reloader=False).

Those can also be passed as arguments to app.run: app.run(debug=True, use_reloader=False).

Thomas Orozco
  • 53,284
  • 11
  • 113
  • 116
  • 1
    Thank you for your answer. Can you add a little code sample / documentation link about how to close the server properly in a separate thread ? – FunkySayu Jul 07 '15 at 10:11
  • 2
    @FunkySayu Typically you'll create a `/shutdown` route. The route code does: `flask.request.environ.get('werkzeug.server.shutdown')()`. To shutdown the server you simply make a HTTP request to `/shutdown`. For security you'll usually add a token that only your app knows so that no one else can shut down the server (and you call `/shutdown?token=somethingSecret`) – Thomas Orozco Jul 07 '15 at 10:14
  • Okay that's what explained the answer below. Now I got it. Thank you for your help. – FunkySayu Jul 07 '15 at 10:15
  • but it's useful reload server when code changes, can I use both of them – Pegasus Nov 22 '17 at 11:19
  • Then how do you stop ? – agemO Oct 10 '18 at 13:16
  • this just disables the nice error view in the browser, but on flask console i still get the `ValueError: signal only works in main thread` – Sonic Soul Sep 04 '19 at 21:10
52

Updated answer for Python 3 that's a bit simpler:

from flask import Flask                                                         
import threading

data = 'foo'
host_name = "0.0.0.0"
port = 23336
app = Flask(__name__)

@app.route("/")
def main():
    return data

if __name__ == "__main__":
    threading.Thread(target=lambda: app.run(host=host_name, port=port, debug=True, use_reloader=False)).start()
skeller88
  • 4,276
  • 1
  • 32
  • 34
20

If you are looking for accessing iPython terminal in Flask run your application in a separate thread. Try this example:

from flask import Flask                                                         
import thread

data = 'foo'
app = Flask(__name__)

@app.route("/")
def main():
    return data

def flaskThread():
    app.run()

if __name__ == "__main__":
    thread.start_new_thread(flaskThread, ())

(Run this file in iPython)

Preston Badeer
  • 2,658
  • 1
  • 20
  • 21
Rashid Mv
  • 396
  • 3
  • 8
3

From the werkzeug documentation:

Shutting Down The Server

New in version 0.7.

Starting with Werkzeug 0.7 the development server provides a way to shut down the server after a request. This currently only works with Python 2.6 and later and will only work with the development server. To initiate the shutdown you have to call a function named 'werkzeug.server.shutdown' in the WSGI environment:

def shutdown_server(environ):
    if not 'werkzeug.server.shutdown' in environ:
        raise RuntimeError('Not running the development server')
    environ['werkzeug.server.shutdown']()
Burhan Khalid
  • 169,990
  • 18
  • 245
  • 284
  • 1
    I don't get your answer. In what I understood, this is a way to stop the server, but my issue is not only how to stop the server but also how to start it. Could you add a little example please ? – FunkySayu Jul 07 '15 at 09:58
1

The original question was about how to run in a thread, and other answers address this, simply make sure to use_reloader=False. However graceful server shutdown when running in a thread I've still not found an answer to. One answer seems outdated as link to the current version of werkzeug shutting down the server suggests using a multiprocess.Process and calling terminate on that process.

I'm interested if anyone has a solution to graceful server shutdown when the flask app is running in a thread instead of a subprocess.

zuleunut
  • 11
  • 3