Oliver Mohr Bonometti
Oliver Mohr Bonometti

Reputation: 587

Python Windows Service (pywin32) works in debug mode but fails as an installed Windows Service

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

Answers (1)

Oyinlade Demola
Oyinlade Demola

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

Related Questions