I have a flask/gevent SocketIOServer and need to make it work as a service:
class TeleportService(win32serviceutil.ServiceFramework):
_svc_name_ = "TeleportServer"
_svc_display_name_ = "Teleport Database Backup Service"
_svc_description_ = "More info at www.elmalabarista.com/teleport"
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def SvcDoRun(self):
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED, (self._svc_name_, ''))
self.ReportServiceStatus(win32service.SERVICE_RUNNING)
runServer()
@werkzeug.serving.run_with_reloader
def runServer():
print 'Listening on %s...' % WEB_PORT
ws = SocketIOServer(('0.0.0.0', WEB_PORT),
SharedDataMiddleware(app, {}),
resource="socket.io",
policy_server=False)
gevent.spawn(runTaskManager).link_exception(lambda *args: sys.exit("important_greenlet died"))
ws.serve_forever()
However, I can't figure how stop it from SvcStop, and running it have the weird behaviour that the service parsing of command line parameters happend AFTER the runserver is killed. This mean the flask server run, I can acces from the web browser but the Service Manager listed it as "Not Started". For example, running in the command line:
C:\Proyectos\TeleportServer>python service.py uninstall <--BAD PARAM, TO MAKE IT OBVIOUS
2013-02-13 16:19:30,786 - DEBUG: Connecting to localhost:9097
* Restarting with reloader
2013-02-13 16:19:32,650 - DEBUG: Connecting to localhost:9097
Listening on 5000...
Growl not available: Teleport Backup Server is started
KeyboardInterrupt <--- HERE I INTERRUPT WITH CTRL-C
Unknown command - 'uninstall'
Usage: 'service.py [options] install|update|remove|start [...]|stop|restart [...
]|debug [...]'
Options for 'install' and 'update' commands only:
--username domain\username : The Username the service is to run under
--password password : The password for the username
--startup [manual|auto|disabled] : How the service starts, default = manual
--interactive : Allow the service to interact with the desktop.
--perfmonini file: .ini file to use for registering performance monitor data
With the suggestion of remove the live reloader, this is the code left. Still, same problem
def SvcDoRun(self): servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,servicemanager.PYS_SERVICE_STARTED,(self._svc_name_, ''))
#self.timeout = 640000 #640 seconds / 10 minutes (value is in milliseconds)
self.timeout = 6000 #120 seconds / 2 minutes
# This is how long the service will wait to run / refresh itself (see script below)
notify.debug("Starting service")
ws = getServer()
while 1:
# Wait for service stop signal, if I timeout, loop again
gevent.sleep(0)
rc = win32event.WaitForSingleObject(self.hWaitStop, self.timeout)
# Check to see if self.hWaitStop happened
if rc == win32event.WAIT_OBJECT_0:
# Stop signal encountered
notify.debug("Stopping service")
ws.kill()
servicemanager.LogInfoMsg("TeleportService - STOPPED!") #For Event Log
break
else:
notify.debug("Starting web server")
ws.serve_forever()
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With