flask: stop server after exception
Question:
I would like to stop my flask server as soon as an unhandled exception occurs.
Here is an example:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
1/0 # argh, exception
return 'Hello World!'
if __name__ == '__main__':
app.run(port=12345)
If you run this and go to localhost:12345, your browser tells you “internal server error” and the python console logs a DivisionByZero
exception.
But the server app doesn’t crash. Flask wraps your routes into its own error handling and it only prints the exception.
I would like to make the server stop as soon as a route produces an exception. But I didn’t find this behaviour in the API. You can specify an errorhandler but that is only to give custom error messages to the client after your route failed.
Answers:
Stopping Flask requires getting into Werkzeug internals. See http://flask.pocoo.org/snippets/67/
Extracted from a single-user app:
from flask import request
@app.route('/quit')
def shutdown():
...
shutdown_hook = request.environ.get('werkzeug.server.shutdown')
if shutdown_hook is not None:
shutdown_hook()
return Response("Bye", mimetype='text/plain')
The shutdown_hook
bit is what you’d need in an exception handler.
from multiprocessing import Process
server = Process(target=app.run)
server.start()
# ...
server.terminate()
server.join()
or if Threaded to run Flask Web Server in background around other python code:
import threading
import ctypes
webserverurl = 127.0.0.1
webserverport = 8080
class thread_with_exception(threading.Thread):
def __init__(self, name):
threading.Thread.__init__(self)
self.name = name
self.interval = 1
self.daemon = True
def __del__(self):
print(f"Thread terminated");
def run(self):
# target function of the thread class
try:
while True:
print(f"{self.name} Waiting for Web")
app.run(host=webserverurl, port=webserverport)
finally:
print('ended')
def get_id(self):
# returns id of the respective thread
if hasattr(self, '_thread_id'):
return self._thread_id
for id, thread in threading._active.items():
if thread is self:
return id
def raise_exception(self):
thread_id = self.get_id()
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(thread_id), ctypes.py_object(SystemExit))
print(f"{self.name} terminated")
if res > 1:
ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(thread_id), 0)
print('Exception raise failure')
t1 = thread_with_exception('Web Server 1')
t1.start()
time.sleep(10)
t1.raise_exception()
# del t1
credit to Andrew Abrahamowicz here:
https://code.activestate.com/recipes/496960-thread2-killable-threads
ctypes.c_long(
required for Linux else Windows only: https://stackoverflow.com/a/61638782/3426192
- other ways to do this here: https://w3guides.com/tutorial/how-to-close-a-flask-web-server-with-python
I would like to stop my flask server as soon as an unhandled exception occurs.
Here is an example:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
1/0 # argh, exception
return 'Hello World!'
if __name__ == '__main__':
app.run(port=12345)
If you run this and go to localhost:12345, your browser tells you “internal server error” and the python console logs a DivisionByZero
exception.
But the server app doesn’t crash. Flask wraps your routes into its own error handling and it only prints the exception.
I would like to make the server stop as soon as a route produces an exception. But I didn’t find this behaviour in the API. You can specify an errorhandler but that is only to give custom error messages to the client after your route failed.
Stopping Flask requires getting into Werkzeug internals. See http://flask.pocoo.org/snippets/67/
Extracted from a single-user app:
from flask import request
@app.route('/quit')
def shutdown():
...
shutdown_hook = request.environ.get('werkzeug.server.shutdown')
if shutdown_hook is not None:
shutdown_hook()
return Response("Bye", mimetype='text/plain')
The shutdown_hook
bit is what you’d need in an exception handler.
from multiprocessing import Process
server = Process(target=app.run)
server.start()
# ...
server.terminate()
server.join()
or if Threaded to run Flask Web Server in background around other python code:
import threading
import ctypes
webserverurl = 127.0.0.1
webserverport = 8080
class thread_with_exception(threading.Thread):
def __init__(self, name):
threading.Thread.__init__(self)
self.name = name
self.interval = 1
self.daemon = True
def __del__(self):
print(f"Thread terminated");
def run(self):
# target function of the thread class
try:
while True:
print(f"{self.name} Waiting for Web")
app.run(host=webserverurl, port=webserverport)
finally:
print('ended')
def get_id(self):
# returns id of the respective thread
if hasattr(self, '_thread_id'):
return self._thread_id
for id, thread in threading._active.items():
if thread is self:
return id
def raise_exception(self):
thread_id = self.get_id()
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(thread_id), ctypes.py_object(SystemExit))
print(f"{self.name} terminated")
if res > 1:
ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(thread_id), 0)
print('Exception raise failure')
t1 = thread_with_exception('Web Server 1')
t1.start()
time.sleep(10)
t1.raise_exception()
# del t1
credit to Andrew Abrahamowicz here:
https://code.activestate.com/recipes/496960-thread2-killable-threads
ctypes.c_long(
required for Linux else Windows only: https://stackoverflow.com/a/61638782/3426192
- other ways to do this here: https://w3guides.com/tutorial/how-to-close-a-flask-web-server-with-python