How make a python windows service of a flask/gevent.socketio server?
To stop it from SvcStop you need to store a reference to "ws" in a global variable (that is, somewhere where it can be retrieved later on). AFAIK "ws.kill()" should then end the loop.
The run_with_reloader decorator appears to run the decorated function immediately, which would explain why the command-line is processed after running the web server. Do you need auto reloading, appearently the decorator only needed when you need reloading.
UPDATE: added example service code
In a project not using flask or gevent I use something like this (with lots of details removed):
class Service (win32serviceutil.ServiceFramework): def __init__(self, *args, **kwds): self._mainloop = None win32serviceutil.ServiceFramework.__init__(self, *args, **kwds) def SvcStop(self): self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) if self._mainloop is not None: self._mainloop.shutdown() def SvcStart(self): self.ReportServiceStatus(win32service.SERVICE_START_PENDING) self._mainloop = ... .MainLoop() self.ReportServiceStatus(win32service.SERVICE_RUNNING) try: self._mainloop.run_forever() finally: self.ReportServiceStatus(win32service.SERVICE_STOPPED)win32serviceutil.HandleCommandLine(Service)
The method serve_forever
comes from BaseServer.serve_forever
. To stop it, you must call BaseServer.shutdown()
or a derivative of it.
In short, you must declare ws
in the global scope. Putting this code before your Service
class definition is one way to do it.
ws = None
Then change your Service.SvcStop
implementation to this :
def SvcStop(self): self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) #Tell the serve_forever() loop to stop and wait until it does. ws.shutdown()
Since ws.shutdown()
already waits for the listener to stop, you can get rid of self.hWaitStop
, unless you use it somewhere else in your code.
Requires Python 2.6+
I can't access WSGIRequestHandler
in Flask outside request
, so I use Process
.
import win32serviceutilimport win32serviceimport win32eventimport servicemanagerfrom multiprocessing import Processfrom app import appclass Service(win32serviceutil.ServiceFramework): _svc_name_ = "TestService" _svc_display_name_ = "Test Service" _svc_description_ = "Tests Python service framework by receiving and echoing messages over a named pipe" def __init__(self, *args): super().__init__(*args) def SvcStop(self): self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING) self.process.terminate() self.ReportServiceStatus(win32service.SERVICE_STOPPED) def SvcDoRun(self): self.process = Process(target=self.main) self.process.start() self.process.run() def main(self): app.run()if __name__ == '__main__': win32serviceutil.HandleCommandLine(Service)