Help: how to run python applications as NT service?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • zxo102

    #1

    Help: how to run python applications as NT service?

    Hi there,
    I have a python application (many python scripts) and I start the
    application like this

    python myServer.py start

    in window. It is running in dos window. Now I would like to put it in
    background as NT service. I got a example code: SmallestService .py from
    chapter 18 of the book "Python Programming On Win32" by Mark Hammond
    etc. The code is as follows and runs well as an NT service.

    Since I don't have the book, anybody knows how to "insert" my "python
    myServer.py start" into the sample code as follows.

    Thanks a lot for your help.

    ouyang

    ############### ############### ############### ########
    import win32serviceuti l
    import win32service
    import win32event

    class SmallestPythonS ervice(win32ser viceutil.Servic eFramework):
    _svc_name_ = "SmallestPython Service"
    _svc_display_na me_ = "The smallest possible Python Service"
    def __init__(self, args):
    win32serviceuti l.ServiceFramew ork.__init__(se lf, args)
    # Create an event which we will use to wait on.
    # The "service stop" request will set this event.
    self.hWaitStop = win32event.Crea teEvent(None, 0, 0, None)

    def SvcStop(self):
    # Before we do anything, tell the SCM we are starting the stop
    process.
    self.ReportServ iceStatus(win32 service.SERVICE _STOP_PENDING)
    # And set my event.
    win32event.SetE vent(self.hWait Stop)

    def SvcDoRun(self):
    # We do nothing other than wait to be stopped!
    win32event.Wait ForSingleObject (self.hWaitStop ,
    win32event.INFI NITE)

    if __name__=='__ma in__':
    win32serviceuti l.HandleCommand Line(SmallestPy thonService)

  • gene tani

    #2
    Re: Help: how to run python applications as NT service?


    zxo102 wrote:[color=blue]
    > Hi there,
    > I have a python application (many python scripts) and I start the
    > application like this
    >
    > python myServer.py start
    >
    > in window. It is running in dos window. Now I would like to put it in
    > background as NT service. I got a example code: SmallestService .py from
    > chapter 18 of the book "Python Programming On Win32" by Mark Hammond
    > etc. The code is as follows and runs well as an NT service.
    >
    > Since I don't have the book, anybody knows how to "insert" my "python
    > myServer.py start" into the sample code as follows.
    >
    > Thanks a lot for your help.
    >
    > ouyang
    >
    > ############### ############### ############### ########
    > import win32serviceuti l
    > import win32service
    > import win32event
    >
    > class SmallestPythonS ervice(win32ser viceutil.Servic eFramework):
    > _svc_name_ = "SmallestPython Service"
    > _svc_display_na me_ = "The smallest possible Python Service"
    > def __init__(self, args):
    > win32serviceuti l.ServiceFramew ork.__init__(se lf, args)
    > # Create an event which we will use to wait on.
    > # The "service stop" request will set this event.
    > self.hWaitStop = win32event.Crea teEvent(None, 0, 0, None)
    >
    > def SvcStop(self):
    > # Before we do anything, tell the SCM we are starting the stop
    > process.
    > self.ReportServ iceStatus(win32 service.SERVICE _STOP_PENDING)
    > # And set my event.
    > win32event.SetE vent(self.hWait Stop)
    >
    > def SvcDoRun(self):
    > # We do nothing other than wait to be stopped!
    > win32event.Wait ForSingleObject (self.hWaitStop ,
    > win32event.INFI NITE)
    >
    > if __name__=='__ma in__':
    > win32serviceuti l.HandleCommand Line(SmallestPy thonService)[/color]

    look at ASPN activestate (online cookbook) recipes linked in this
    thread (sorry i don't do those qURL things)



    Comment

    • Larry Bates

      #3
      Re: Help: how to run python applications as NT service?

      zxo102 wrote:[color=blue]
      > Hi there,
      > I have a python application (many python scripts) and I start the
      > application like this
      >
      > python myServer.py start
      >
      > in window. It is running in dos window. Now I would like to put it in
      > background as NT service. I got a example code: SmallestService .py from
      > chapter 18 of the book "Python Programming On Win32" by Mark Hammond
      > etc. The code is as follows and runs well as an NT service.
      >
      > Since I don't have the book, anybody knows how to "insert" my "python
      > myServer.py start" into the sample code as follows.
      >
      > Thanks a lot for your help.
      >
      > ouyang
      >
      > ############### ############### ############### ########
      > import win32serviceuti l
      > import win32service
      > import win32event
      >
      > class SmallestPythonS ervice(win32ser viceutil.Servic eFramework):
      > _svc_name_ = "SmallestPython Service"
      > _svc_display_na me_ = "The smallest possible Python Service"
      > def __init__(self, args):
      > win32serviceuti l.ServiceFramew ork.__init__(se lf, args)
      > # Create an event which we will use to wait on.
      > # The "service stop" request will set this event.
      > self.hWaitStop = win32event.Crea teEvent(None, 0, 0, None)
      >
      > def SvcStop(self):
      > # Before we do anything, tell the SCM we are starting the stop
      > process.
      > self.ReportServ iceStatus(win32 service.SERVICE _STOP_PENDING)
      > # And set my event.
      > win32event.SetE vent(self.hWait Stop)
      >
      > def SvcDoRun(self):
      > # We do nothing other than wait to be stopped!
      > win32event.Wait ForSingleObject (self.hWaitStop ,
      > win32event.INFI NITE)
      >
      > if __name__=='__ma in__':
      > win32serviceuti l.HandleCommand Line(SmallestPy thonService)
      >[/color]

      Basically you insert your python program code inside the SvcDoRun
      method of this service. You will, of course, have to change it to
      act like class method code instead of regular main program code.
      You can then register it and start/stop it like any other service.

      The other part you add is code about how often you want the service
      to wake up and run the SvcDoRun method. Normally you wouldn't
      use win32event.INFI NITE but rather wait some number of milliseconds
      before running a second time. The example just waits for a stop
      signal.


      Here is a skeleton of a service that should get you started. I
      HIGHLY recommend spending the money to purchase the book
      (Python Programming on WIN32). There are more extensive examples
      than the one you have that would help you a lot.

      Hope this helps.
      Larry Bates

      import win32serviceuti l
      import win32service
      import win32event
      import win32evtlogutil


      class Yourservice(win 32serviceutil.S erviceFramework ):
      # Indent all code below 4 spaces
      def SvcDoRun(self):
      import servicemanager
      #------------------------------------------------------
      # Make entry in the event log that this service started
      #------------------------------------------------------
      servicemanager. LogMsg(servicem anager.EVENTLOG _INFORMATION_TY PE,
      servicemanager. PYS_SERVICE_STA RTED,
      (self._svc_name _, ''))

      #-------------------------------------------------------------
      # Set an amount of time to wait (in milliseconds) between runs
      #-------------------------------------------------------------
      self.timeout=60 000 (60 seconds)
      while 1:
      #-------------------------------------------------------
      # Wait for service stop signal, if I timeout, loop again
      #-------------------------------------------------------
      rc=win32event.W aitForSingleObj ect(self.hWaitS top, self.timeout)
      #
      # Check to see if self.hWaitStop happened
      #
      if rc == win32event.WAIT _OBJECT_0:
      #
      # Stop signal encountered
      #
      break

      else:
      #
      # Put your code here
      #

      #
      # Only return from SvcDoRun when you wish to stop
      #
      return


      def SvcStop(self):
      #---------------------------------------------------------------------
      # Before we do anything, tell SCM we are starting the stop process.
      #---------------------------------------------------------------------
      self.ReportServ iceStatus(win32 service.SERVICE _STOP_PENDING)
      #---------------------------------------------------------------------
      # And set my event
      #---------------------------------------------------------------------
      win32event.SetE vent(self.hWait Stop)
      return

      Comment

      • zxo102

        #4
        Re: Help: how to run python applications as NT service?


        Thanks for your help, Larry.

        Finally, I got it my python script run as NT service with
        the attached python code which is from the site:




        ############### ############### ############### ############### ############### ###
        #
        # Copyright (c) 2005 Zope Corporation and Contributors.
        # All Rights Reserved.
        #
        # This software is subject to the provisions of the Zope Public
        License,
        # Version 2.1 (ZPL). A copy of the ZPL should accompany this
        distribution.
        # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
        # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
        # WARRANTIES OF TITLE, MERCHANTABILITY , AGAINST INFRINGEMENT, AND
        FITNESS
        # FOR A PARTICULAR PURPOSE.
        #
        ############### ############### ############### ############### ############### ###

        """
        Windows NT/2K service installer/controller for Zope/ZEO/ZRS instances.
        """

        # With trivial modifications for use with SchoolBell and SchoolTool.

        import sys, os, time
        import pywintypes
        import win32serviceuti l
        import win32service
        import win32event
        import win32process

        # the max seconds we're allowed to spend backing off
        BACKOFF_MAX = 300
        # if the process runs successfully for more than BACKOFF_CLEAR_T IME
        # seconds, we reset the backoff stats to their initial values
        BACKOFF_CLEAR_T IME = 30
        # the initial backoff interval (the amount of time we wait to restart
        # a dead process)
        BACKOFF_INITIAL _INTERVAL = 5

        class Service(win32se rviceutil.Servi ceFramework):
        """ A class representing a Windows NT service that can manage an
        instance-home-based Zope/ZEO/ZRS processes """

        # The comment below is mostly irrelevant if you're running a
        standalone
        # SchoolBell server, I think. -TEH

        # The PythonService model requires that an actual on-disk class
        declaration
        # represent a single service. Thus, the below definition of
        start_cmd,
        # must be overridden in a subclass in a file within the instance
        home for
        # each instance. The below-defined start_cmd (and
        _svc_display_na me_
        # and _svc_name_) are just examples.

        # To use this script with SchoolTool, just replace "SchoolBell "
        # with "SchoolTool " in the variables below.
        # You'll also need to change 'Python24' to 'Python23' if that's
        # what you've got. -TEH

        _svc_name_ = r'SchoolBell'
        _svc_display_na me_ = r'SchoolBell Server'

        start_cmd = (
        r'"C:\Python24\ python.exe" '
        r'"C:\Program Files\SchoolBel l\schoolbell-server.py" '
        )

        def __init__(self, args):
        win32serviceuti l.ServiceFramew ork.__init__(se lf, args)
        # Create an event which we will use to wait on.
        # The "service stop" request will set this event.
        self.hWaitStop = win32event.Crea teEvent(None, 0, 0, None)
        self.redirectOu tput()

        def redirectOutput( self):
        sys.stdout.clos e()
        sys.stderr.clos e()
        sys.stdout = NullOutput()
        sys.stderr = NullOutput()

        def SvcStop(self):
        # Before we do anything, tell the SCM we are starting the stop
        process.
        self.ReportServ iceStatus(win32 service.SERVICE _STOP_PENDING)

        # TODO: This TerminateProces s call doesn't make much sense:
        it's
        # doing a hard kill _first_, never giving the process a chance
        to
        # shut down cleanly. Compare to current Zope2 service code,
        which
        # uses Windows events to give the process a chance to shut down
        # cleanly, doing a hard kill only if that doesn't succeed.

        # stop the process if necessary
        try:
        win32process.Te rminateProcess( self.hZope, 0)
        except pywintypes.erro r:
        # the process may already have been terminated
        pass
        # And set my event.
        win32event.SetE vent(self.hWait Stop)

        # SvcStop only gets triggered when the user explictly stops (or
        restarts)
        # the service. To shut the service down cleanly when Windows is
        shutting
        # down, we also need to hook SvcShutdown.
        SvcShutdown = SvcStop

        def createProcess(s elf, cmd):
        return win32process.Cr eateProcess(
        None, cmd, None, None, 0, 0, None, None,
        win32process.ST ARTUPINFO())

        def SvcDoRun(self):
        # indicate to Zope that the process is daemon managed
        (restartable)
        os.environ['ZMANAGED'] = '1'

        # daemon behavior: we want to to restart the process if it
        # dies, but if it dies too many times, we need to give up.

        # we use a simple backoff algorithm to determine whether
        # we should try to restart a dead process: for each
        # time the process dies unexpectedly, we wait some number of
        # seconds to restart it, as determined by the backoff interval,
        # which doubles each time the process dies. if we exceed
        # BACKOFF_MAX seconds in cumulative backoff time, we give up.
        # at any time if we successfully run the process for more thab
        # BACKOFF_CLEAR_T IME seconds, the backoff stats are reset.

        # the initial number of seconds between process start attempts
        backoff_interva l = BACKOFF_INITIAL _INTERVAL
        # the cumulative backoff seconds counter
        backoff_cumulat ive = 0

        import servicemanager

        # log a service started message
        servicemanager. LogMsg(
        servicemanager. EVENTLOG_INFORM ATION_TYPE,
        servicemanager. PYS_SERVICE_STA RTED,
        (self._svc_name _, ' (%s)' % self._svc_displ ay_name_))

        while 1:
        start_time = time.time()
        info = self.createProc ess(self.start_ cmd)
        self.hZope = info[0] # the pid
        if backoff_interva l > BACKOFF_INITIAL _INTERVAL:
        # if we're in a backoff state, log a message about
        # starting a new process
        servicemanager. LogInfoMsg(
        '%s (%s): recovering from died process, new process
        '
        'started' % (self._svc_name _,
        self._svc_displ ay_name_)
        )
        rc = win32event.Wait ForMultipleObje cts(
        (self.hWaitStop , self.hZope), 0, win32event.INFI NITE)
        if rc == win32event.WAIT _OBJECT_0:
        # user sent a stop service request
        self.SvcStop()
        break
        else:
        # user did not send a service stop request, but
        # the process died; this may be an error condition
        status = win32process.Ge tExitCodeProces s(self.hZope)
        if status == 0:
        # the user shut the process down from the web
        # interface (or it otherwise exited cleanly)
        break
        else:
        # this was an abormal shutdown. if we can, we want
        to
        # restart the process but if it seems hopeless,
        # don't restart an infinite number of times.
        if backoff_cumulat ive > BACKOFF_MAX:
        # it's hopeless
        servicemanager. LogErrorMsg(
        '%s (%s): process could not be restarted due
        to max '
        'restart attempts exceeded' % (
        self._svc_displ ay_name_, self._svc_name_
        ))
        self.SvcStop()
        break
        servicemanager. LogWarningMsg(
        '%s (%s): process died unexpectedly. Will
        attempt '
        'restart after %s seconds.' % (
        self._svc_name_ , self._svc_displ ay_name_,
        backoff_interva l
        )
        )
        # if BACKOFF_CLEAR_T IME seconds have elapsed since
        we last
        # started the process, reset the backoff interval
        # and the cumulative backoff time to their original
        # states
        if time.time() - start_time > BACKOFF_CLEAR_T IME:
        backoff_interva l = BACKOFF_INITIAL _INTERVAL
        backoff_cumulat ive = 0
        # we sleep for the backoff interval. since this is
        async
        # code, it would be better done by sending and
        # catching a timed event (a service
        # stop request will need to wait for us to stop
        sleeping),
        # but this works well enough for me.
        time.sleep(back off_interval)
        # update backoff_cumulat ive with the time we spent
        # backing off.
        backoff_cumulat ive = backoff_cumulat ive +
        backoff_interva l
        # bump the backoff interval up by 2* the last
        interval
        backoff_interva l = backoff_interva l * 2

        # loop and try to restart the process

        # log a service stopped message
        servicemanager. LogMsg(
        servicemanager. EVENTLOG_INFORM ATION_TYPE,
        servicemanager. PYS_SERVICE_STO PPED,
        (self._svc_name _, ' (%s) ' % self._svc_displ ay_name_))


        class NullOutput:
        """A stdout / stderr replacement that discards everything."""

        def noop(self, *args, **kw):
        pass

        write = writelines = close = seek = flush = truncate = noop

        def __iter__(self):
        return self

        def next(self):
        raise StopIteration

        def isatty(self):
        return False

        def tell(self):
        return 0

        def read(self, *args, **kw):
        return ''

        readline = read

        def readlines(self, *args, **kw):
        return []


        if __name__=='__ma in__':
        win32serviceuti l.HandleCommand Line(Service)

        Comment

        Working...