Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I terminate a flask app that's running as a service?

I was able to get my flask app running as a service thanks to Is it possible to run a Python script as a service in Windows? If possible, how?, but when it comes to stopping it i cannot. I have to terminate the process in task manager.

Here's my run.py which I turn into a service via run.py install:

from app import app

from multiprocessing import Process
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket


class AppServerSvc (win32serviceutil.ServiceFramework):
    _svc_name_ = "CCApp"
    _svc_display_name_ = "CC App"

    def __init__(self,args):
        win32serviceutil.ServiceFramework.__init__(self,args)
        self.hWaitStop = win32event.CreateEvent(None,0,0,None)
        socket.setdefaulttimeout(60)

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)
        server.terminate()
        server.join()

    def SvcDoRun(self):
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                              servicemanager.PYS_SERVICE_STARTED,
                              (self._svc_name_,''))
        self.main()

    def main(self):
        server = Process(app.run(host = '192.168.1.6'))
        server.start()

if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(AppServerSvc)

I got the process stuff from this post: http://librelist.com/browser/flask/2011/1/10/start-stop-flask/#a235e60dcaebaa1e134271e029f801fe but unfortunately it doesn't work either.

The log file in Event Viewer says that the global variable 'server' is not defined. However, i've made server a global variable and it still gives me the same error.

like image 571
Chockomonkey Avatar asked May 09 '14 00:05

Chockomonkey


3 Answers

You can stop the Werkzeug web server gracefully before you stop the Win32 server. Example:

from flask import request

def shutdown_server():
    func = request.environ.get('werkzeug.server.shutdown')
    if func is None:
        raise RuntimeError('Not running with the Werkzeug Server')
    func()

@app.route('/shutdown', methods=['POST'])
def shutdown():
    shutdown_server()
    return 'Server shutting down...'

If you add this to your Flask server you can then request a graceful server shutdown by sending a POST request to /shutdown. You can use requests or urllib2 to do this. Depending on your situation you may need to protect this route against unauthorized access.

Once the server has stopped I think you will have to no problem stopping the Win32 service.

Note that the shutdown code above appears in this Flask snippet.

like image 56
Miguel Avatar answered Oct 18 '22 15:10

Miguel


You could also trick Flask into believing you pressed Ctrl + C:

def shutdown_flask(self):
    from win32api import GenerateConsoleCtrlEvent
    CTRL_C_EVENT = 0
    GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0)

Then simply call shutdown_flask() in your SvcStop():

try:
    # try to exit gracefully
    self.shutdown_flask()
except Exception as e:
    # force quit
    os._exit(0)

Should shutdown_flask() fail for some reason, os._exit() makes sure your service will end (albeit with a nasty warning), by halting the interpreter.

like image 25
JohnTheWalker Avatar answered Oct 18 '22 15:10

JohnTheWalker


I recommend you use http://supervisord.org/. Actually not work in Windows, but with Cygwin you can run supervisor as in Linux, including run as service.

For install Supervisord: https://stackoverflow.com/a/18032347/3380763

After install you must configure the app, here an example: http://flaviusim.com/blog/Deploying-Flask-with-nginx-uWSGI-and-Supervisor/ (Is not necessary that you use Nginx with the Supervisor's configuration is enough)

like image 43
yograterol Avatar answered Oct 18 '22 16:10

yograterol