I have a program written in Python that I want to run as a windows service. The program find routes for cables in a database which holds the cables and the nodal network. The program can be run as an endless loop and made to point at a specific schema or project, via a command line argument.
Now what I need to do is to make it so I can install multiple instances of the same program as services, but provide a different name each time, so that each one is installed as a separate service under the specified name. The name will also point the program towards the correct schema in the database, so the name needs to be recovered and passed as an argument when SVCStart and Stop are called. Note also that one instance of the program is used to halt another one, by sending a message via the database.
I'm struggling to figure out how to use the win32serviceutil.ServiceFramework to do this. I tried using global variables as you can see, but as installation and startup are separate they aren't preserved. I'm starting to think I may have to save this name to some kind of log file as I can't find a way of preserving it in the code. Another approach is maybe to dig a bit deeper into the service framework and see if I can't customise things a bit more to suit my needs, but the minimal documentation available online is making this difficult for a beginner like myself.
I've included my latest attempt at the end of this, it doesn't work and I have a good idea why, I'm looking for suggestions on how to move forward more than anything. I am a rookie software developer with no formal training so please be gentle, and any explanations of the underlying mechanics of windows services which might be relevant to my problem would be much appreciated.
Thanks
import win32serviceutil
import win32service
import win32event
import os
import sys
import argparse
import subprocess
AUTOROUTER_SCRIPT = r'\simple_test.py'
PYTHON_EXE = 'python'
service_name = "ARServicePlaceHolderName"
service_display_name = "AutorouterPlaceHolder"
service_description = "Autorouter"
class ARService(win32serviceutil.ServiceFramework):
_svc_name_ = service_name
_svc_display_name_ = service_display_name
_svc_description_ = service_description
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
directory = os.path.dirname(os.path.abspath(__file__))
self.ar_path = os.path.join(directory, AUTOROUTER_SCRIPT)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
self.autorouter_process = None
def SvcDoRun(self):
command = [PYTHON_EXE, self.ar_path, self._svc_name]
self.autorouter_process = subprocess.Popen(command)
win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
command = [PYTHON_EXE, self.ar_path, self._svc_name, '--halt']
halt_process = subprocess.Popen(command)
halt_process.wait()
self.autorouter_process.wait()
self.autorouter_process = None
win32event.SetEvent(self.hWaitStop)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('name', help='Name daemon by schema or projid')
args, unknown_args = parser.parse_known_args()
service_name = 'AutoRouter' + args.name
service_display_name = 'AutoRouter for ' + args.name
service_description = 'AutoRouter for ' + args.name
# Remove name argument from sys.argv before calling HandleCommandLine
sys.argv[1:] = unknown_args
win32serviceutil.HandleCommandLine(ARService)