3

I have used this question to learn install my python script as a service with ActivePython. I am able to install my script and remove it, as I would expect, but my problem is that once I start the script running, I then lose the ability to stop it or remove it. It just runs permanently and I cannot get rid of it. The answer to the linked question mentions checking a flag to stop the script. Can someone explain how to do this?

Right now the script does very little. just prints lines to a file every few seconds. I want to get it working before I move on to more complicated things.

import pythoncom
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
import time


class AppServerSvc (win32serviceutil.ServiceFramework):
    _svc_name_ = "PythonTest"
    _svc_display_name_ = "Python Test"
    _svc_description_ = "This is a test of installing Python services"

    def __init__(self,args):
        win32serviceutil.ServiceFramework.__init__(self,args)
        self.hWaitStop = win32event.CreateEvent(None,0,0,None)
        socket.setdefaulttimeout(60)

    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.main()

    def main(self):
        i=0
        while True:
            f=open("C:\\hello.txt","a")
            f.write("hello"+str(i)+"\n")
            f.close()
            i=i+1
            time.sleep(5)


if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(AppServerSvc)
Community
  • 1
  • 1
ewok
  • 20,148
  • 51
  • 149
  • 254
  • I might suggest that [this ActiveState recipe](http://code.activestate.com/recipes/551780/) simplifies writing simple Windows services greatly. – ig0774 Oct 28 '11 at 15:07

2 Answers2

6

Of course you can't stop it, you're stuck in an infinite loop. Replace:

time.sleep(5)

with this:

if win32event.WaitForSingleObject(self.hWaitStop, 5000) == win32event.WAIT_OBJECT_0: 
    break

Should do the trick.

ewok
  • 20,148
  • 51
  • 149
  • 254
fraca7
  • 1,178
  • 5
  • 11
  • Thanks. That worked. Any idea how to get rid of the service that I installed before I fixed this? – ewok Oct 28 '11 at 15:08
  • If you edited the script and relaunched the service the new code should take over. If you're talking about instances of the previous version, just launch Task Manager (Ctrl+Shift+Escape) and kill the relevant processes; they should be named after your script. Or reboot :) – fraca7 Oct 28 '11 at 18:30
  • 1
    While I'm at it, a more detailed explanation: the SvcDoRun method is actually run in a thread that is separate from the one which called __init__. When the service manager calls SvcStop, it's still in another thread. So you have to set the event in SvcStop but also check if it's set in SvcDoRun in order to exit the thread when Windows tells you to. – fraca7 Oct 28 '11 at 18:35
0

"Checking a flag" means having the script (inside the while True loop) look for something, almost anything, as a signal to break out of the loop. It could check for the existence of a file with a particular name and exit when the file is created. As long as you can manually or through a control application create the signal, the service can look for that same signal.

As far as "not being able to stop it", do you mean that it keeps running even if you try to kill it with the Windows task manager?

Dave
  • 3,834
  • 2
  • 29
  • 44
  • Presumably @ewok means that the service cannot be stopped using the services control panel or `net stop` and it's ilk, since with an infinite loop, the service will just continue running. – ig0774 Oct 28 '11 at 14:57