1

I created a service based on this code Is it possible to run a Python script as a service in Windows? If possible, how?
The problem is that I cant stop the service, smoothly.
To stop the service I would need to recheck a flag for a stop event every period of time.
Is there any better way to stop a service in python? This is how I currently try to stop my service.

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_,''))
    myStatusThread = threading.Thread(target=win32event.WaitForSingleObject, args=(self.hWaitStop, win32event.INFINITE))
    myStatusThread.start()
    while True:
        if not myStatusThread.isAlive():
            sys.exit(0)
        else:
            doStuff()#do something that takes some time

So the service only stops once "doStuff" is done, which could take a long time.
I would like to stop the service as soon as the user stops it in the services.

Community
  • 1
  • 1
yuval
  • 2,848
  • 4
  • 31
  • 51
  • what kind of flag are you checking ? – user1767754 Nov 23 '15 at 07:02
  • A service often contains a loop waiting for *something* to happen (connection on a socket, presence of a file. etc.) and processing the *event*. Without knowing what your loop looks like, it is hard to give advices on the way to stop it besides saying *test the f... Stop event*. Could you show the basics of your service? – Serge Ballesta Nov 23 '15 at 07:39
  • I edited my question – yuval Nov 23 '15 at 07:42

2 Answers2

0

It may be better to use NSSM insead of coding this task in winapi:

nssm install my_python_service
nssm set my_python_service Application C:\Python3\python.exe
nssm set my_python_service AppDirectory C:\myscript\
nssm set my_python_sevice AppParameters C:\myscrip\myscript_main_file.py

nssm set my_python_sevice Start SERVICE_AUTO_START
nssm run my_python_service

For stopping service:

nssm stop my_python_service
  • This does not explain why OP could not stop with WINAPI, nor gives any advice on how to gracefully closed a service started with NSSM. And you could at least cite [this answer](http://stackoverflow.com/a/24996607/3545273) on referenced post. – Serge Ballesta Nov 23 '15 at 07:24
0

In fact, your question is double: how can I test an event and how could I smoothly stop a long running routine? Unfortunately, there is no easy and direct answer to second part. The common usage is to manually identify stop points in the code and put there a simple routine that test the event and raise a custom exception. This allows a single place to put some cleanup before exiting.

You code could become (more or less):

class EventException(Exception):
   def __init__(status):
       # allows to know where you exit from in case cleanup depends on it
       self.status = status

and later ...

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 testEvent(self, status):
    if (win32event.win32event.WaitForSingleObject(self.hWaitStop, 0)
            == win32event.WAIT_OBJECT_0):
        raise EventException(status)

def SvcDoRun(self):
    servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
                          servicemanager.PYS_SERVICE_STARTED,
                          (self._svc_name_,''))
    while True:
        # wait the event with a 0ms timeout (ie: just test it)
        evt = win32event.win32event.WaitForSingleObject(self.hWaitStop, 0)
        if evt == win32event.WAIT_OBJECT_0  # event is is signaled state
            sys.exit(0)
        else:
            try:
                self.doStuff()
            except EventException as e:
                status = e.status
                # cleanup potentially dependent on status

def doStuff(self):
    #do something that takes some time
    ...
    # in some places test if we should stop immediatelly
    self.testEvent(status)    # status is an arbitrary value
    ...

That way:

  • you test the event without need for an auxialliary thread
  • you an not forced to wait full processing to stop service
  • you have a net place for cleanup if you stop the service in the middle of processing.
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252