Reputation: 587
I made a websocket echo server and wanted to test it as a running service in the background.
The code for the Windows Service in Python was took from here and it uses pywin32
.
The code works well in debug mode python server.py debug
(meaning client receives message echoed back from server).
When I install it (only admin mode works) with python server.py install
it appears in the Windows Services List, but when I try to start it and error message appear with: "Windows could not start Python Echo WebSocket Server in local Computer. For more info...... error code 536870913."
Base class for Windows Service (SMWinservice.py):
import socket
import win32serviceutil
import servicemanager
import win32event
import win32service
class SMWinservice(win32serviceutil.ServiceFramework):
'''Base class to create winservice in Python'''
_svc_name_ = 'pythonService'
_svc_display_name_ = 'Python Service'
_svc_description_ = 'Python Service Description'
@classmethod
def parse_command_line(cls):
'''
ClassMethod to parse the command line
'''
win32serviceutil.HandleCommandLine(cls)
def __init__(self, args):
'''
Constructor of the winservice
'''
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
socket.setdefaulttimeout(60)
def SvcStop(self):
'''
Called when the service is asked to stop
'''
self.stop()
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def SvcDoRun(self):
'''
Called when the service is asked to start
'''
self.start()
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ''))
self.main()
def start(self):
'''
Override to add logic before the start
eg. running condition
'''
pass
def stop(self):
'''
Override to add logic before the stop
eg. invalidating running condition
'''
pass
def main(self):
'''
Main class to be ovverridden to add logic
'''
pass
# entry point of the module: copy and paste into the new module
# ensuring you are calling the "parse_command_line" of the new created class
if __name__ == '__main__':
SMWinservice.parse_command_line()
Server implementation (server.py):
import asyncio
import websockets
from SMWinservice import SMWinservice
DOMAIN = 'localhost'
PORT = XXX # Replace XXX with integer
class EchoServerService(SMWinservice):
_svc_name_ = "EchoWSService"
_svc_display_name_ = "Python Echo WebSocket Server"
_svc_description_ = "A python written service of a WebSocket Echo Server running in localhost:XXX"
def start(self):
self.isrunning = True
def stop(self):
self.isrunning = False
def process_message(self, message):
print(message)
return message
async def handle(self, ws_client):
async for message in ws_client:
result = self.process_message(message)
await ws_client.send(result)
async def async_main(self):
async with websockets.serve(self.handle, DOMAIN, PORT) as _:
await asyncio.Future()
def main(self):
if self.isrunning:
asyncio.run(self.async_main())
if __name__ == '__main__':
EchoServerService.parse_command_line()
Upvotes: 1
Views: 1263
Reputation: 712
I have experienced a similar issue and my solution is to run the websocket on another thread e.g threading.Thread(target=self.async_main).start()
Upvotes: 0