3

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.

lhk
  • 27,458
  • 30
  • 122
  • 201
  • 1
    specify an errorhandler ... in your errorhandler shutdown the server ... (see: http://flask.pocoo.org/snippets/67/) this doesn't really make much sense as a use case though ... I dont understand why you would want to do this (you definately should not be using `app.run` for anything but developement... do not release that as the way to run your server...) – Joran Beasley Nov 15 '18 at 20:18
  • 3
    This is the intended behavior of a web server -- you would not want your entire website to become unavailable due to one route raising an exception. – Sean Pianka Nov 15 '18 at 20:21
  • I'm currently debugging the server and far from deploying. Don't worry :) After the exception has occured I know that an important resource has become corrupted. It makes no sense to continue after that. Some routes will still come through but the server is essentially down. So after this exception I want to shut it down for good and not waste other resources (some of this is costly) – lhk Nov 15 '18 at 20:43

2 Answers2

0

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.

Dave W. Smith
  • 24,318
  • 4
  • 40
  • 46
0
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

social
  • 329
  • 3
  • 8