Search code examples
pythonflaskatexit

Flask and Web.py both hang on atexit


I have this simple Flask app:

from flask import Flask
import prolog_handler as p

app = Flask(__name__)
app.debug = False

@app.route('/')
def hello():
    for rule in p.rules:
        print rule
    return 'hello'

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)

The prolog_handler module starts a session with a triplestore and loads some rules. It also has an atexit function that ends the session and prints a message like "Closing...". I start the server from the bash prompt with python myapp.py. Whenever I hit CTRL-C to stop the server, nothing happens. I don't get returned back to the bash prompt, and I don't see the "Closing..." message printed. I also tried to do this with Web.py with the same results.

The that prolog_handler does is literally as simple as this:

tstore = openPrologSession()
rules = ...

def cleanUp():
    print "Closing..."
    tstore.endSession()

atexit.register(cleanUp)

So why is it so difficult to just perform an atexit task?

PS: if I comment out all the stuff about opening the Prolog Session and ending it, and just leave the part that prints the message "Closing..." then I do see the "Closing..." message when I hit CTRL-C and I do get returned to the bash prompt. That works as expected. But what's the point of atexit if I can't do anything useful with it?


Solution

  • This may not be the perfect answer but I tried to use the following for Flask:

    # These functions should be called when you tear down the application
    app.teardown_functions = []
    
    def teardown_applications(): 
        for func in app.teardown_functions:
           print('Calling teardown function %s' % func.__name__)
            func()
    
    app.teardown_functions.append(function_tocall_at_exit)
    

    This seems to work for me. I also tend to use gevent for all flask applications

    if __name__ == '__main__':
        gevent.signal(signal.SIGINT, teardown_applications)
        http_server = WSGIServer(('', 5000), app)
        http_server.serve_forever()
    

    This usually works for me.

    Some of the module imports:

    from flask import Flask
    from gevent.wsgi import WSGIServer
    import gevent
    import signal
    
    from gevent import monkey
    monkey.patch_all()