Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Help: how to run python applications as NT service?

91 views
Skip to first unread message

zxo102

unread,
Dec 12, 2005, 11:17:20 AM12/12/05
to
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 win32serviceutil
import win32service
import win32event

class SmallestPythonService(win32serviceutil.ServiceFramework):
_svc_name_ = "SmallestPythonService"
_svc_display_name_ = "The smallest possible Python Service"
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
# Create an event which we will use to wait on.
# The "service stop" request will set this event.
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)

def SvcStop(self):
# Before we do anything, tell the SCM we are starting the stop
process.
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
# And set my event.
win32event.SetEvent(self.hWaitStop)

def SvcDoRun(self):
# We do nothing other than wait to be stopped!
win32event.WaitForSingleObject(self.hWaitStop,
win32event.INFINITE)

if __name__=='__main__':
win32serviceutil.HandleCommandLine(SmallestPythonService)

gene tani

unread,
Dec 12, 2005, 12:32:23 PM12/12/05
to

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

http://groups.google.com/group/comp.lang.python/browse_frm/thread/39e482a3ea7f6041/8ac679d13cf95867?q=windows+service+activestate&rnum=1#8ac679d13cf95867

Larry Bates

unread,
Dec 12, 2005, 3:14:43 PM12/12/05
to zxo102

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.INFINITE 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 win32serviceutil
import win32service
import win32event

import win32evtlogutil


class Yourservice(win32serviceutil.ServiceFramework):
# Indent all code below 4 spaces
def SvcDoRun(self):
import servicemanager
#------------------------------------------------------
# Make entry in the event log that this service started
#------------------------------------------------------
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ''))

#-------------------------------------------------------------
# Set an amount of time to wait (in milliseconds) between runs
#-------------------------------------------------------------
self.timeout=60000 (60 seconds)
while 1:
#-------------------------------------------------------
# Wait for service stop signal, if I timeout, loop again
#-------------------------------------------------------
rc=win32event.WaitForSingleObject(self.hWaitStop, 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.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
#---------------------------------------------------------------------
# And set my event
#---------------------------------------------------------------------
win32event.SetEvent(self.hWaitStop)
return

zxo102

unread,
Dec 14, 2005, 12:13:40 PM12/14/05
to

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:

http://www.schooltool.org/products/schooltool-calendar/documentation/how-to/running-as-a-windows-service/schooltool-service.py/view


##############################################################################
#
# 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 win32serviceutil
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_TIME
# seconds, we reset the backoff stats to their initial values
BACKOFF_CLEAR_TIME = 30
# the initial backoff interval (the amount of time we wait to restart
# a dead process)
BACKOFF_INITIAL_INTERVAL = 5

class Service(win32serviceutil.ServiceFramework):
""" 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_name_
# 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_name_ = r'SchoolBell Server'

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

def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
# Create an event which we will use to wait on.
# The "service stop" request will set this event.
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)

self.redirectOutput()

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

def SvcStop(self):
# Before we do anything, tell the SCM we are starting the stop
process.
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)

# TODO: This TerminateProcess 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.TerminateProcess(self.hZope, 0)
except pywintypes.error:
# the process may already have been terminated
pass


# And set my event.
win32event.SetEvent(self.hWaitStop)

# 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(self, cmd):
return win32process.CreateProcess(
None, cmd, None, None, 0, 0, None, None,
win32process.STARTUPINFO())

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_TIME seconds, the backoff stats are reset.

# the initial number of seconds between process start attempts
backoff_interval = BACKOFF_INITIAL_INTERVAL
# the cumulative backoff seconds counter
backoff_cumulative = 0

import servicemanager

# log a service started message
servicemanager.LogMsg(
servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ' (%s)' % self._svc_display_name_))

while 1:
start_time = time.time()
info = self.createProcess(self.start_cmd)
self.hZope = info[0] # the pid
if backoff_interval > 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_display_name_)
)
rc = win32event.WaitForMultipleObjects(
(self.hWaitStop, self.hZope), 0, win32event.INFINITE)
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.GetExitCodeProcess(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_cumulative > BACKOFF_MAX:
# it's hopeless
servicemanager.LogErrorMsg(
'%s (%s): process could not be restarted due
to max '
'restart attempts exceeded' % (
self._svc_display_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_display_name_,
backoff_interval
)
)
# if BACKOFF_CLEAR_TIME 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_TIME:
backoff_interval = BACKOFF_INITIAL_INTERVAL
backoff_cumulative = 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(backoff_interval)
# update backoff_cumulative with the time we spent
# backing off.
backoff_cumulative = backoff_cumulative +
backoff_interval
# bump the backoff interval up by 2* the last
interval
backoff_interval = backoff_interval * 2

# loop and try to restart the process

# log a service stopped message
servicemanager.LogMsg(
servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STOPPED,
(self._svc_name_, ' (%s) ' % self._svc_display_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__=='__main__':
win32serviceutil.HandleCommandLine(Service)

0 new messages