I was doing a bit of searching today to see what I could dig up to
improve how the development server operates on Windows. I found this
which is pretty close to what I want to do. It comes from Turbo Gears.
Is there any interest from anyone else to help me implement the light
development server as a Window Service?
I plan to rewrite this a bit for Django. I just think it would be
cleaner and logs could be written to file as opposed to stdout. I am not
so familiar with Windows but more Mac and Unix which is reason it would
be nice for someone with Windows to help me out on this. I don't think
it would require too much to provide this functionality. I think in
light of the fact that most people are likely developing on windows
boxes, it would be a plus. I looked at the httpserver code and I don't
think it would much to fit this in.
Regards,
David
From Turbo Gears ...
import cherrypy
import pkg_resources
pkg_resources.require("TurboGears")
import sys
import os
from os.path import *
import win32serviceutil
import win32service
from win32com.client import constants
class TGWindowsService(win32serviceutil.ServiceFramework):
"""TurboGears Windows Service helper class.
The TGWindowsService class contains all the functionality required
for running a TurboGears application as a Windows Service. The only
user edits required for this class are located in the following class
variables:
_svc_name_: The name of the service (used in the Windows
registry).
_svc_display_name_: The name that will appear in the Windows
Service Manager.
code_dir: The full path to the base directory of the user's
TG app code (usually where <project_name>-start.py
and the *.cfg files are located).
root_class: The fully qualified Root class name
(e.g. wiki20.controllers.Root)
log_dir: The desired location of the stdout and stderr
log files.
For information on installing the application, please refer to the
documentation at the end of this module or navigate to the directory
where this module is located and type "service.py" from the command
prompt.
"""
# -- START USER EDIT SECTION
# -- Users must edit this section before installing the service.
_svc_name_ = '' # (Required) The name of the service.
_svc_display_name_ = '' # (Required) The Service Manager display name.
code_dir = r'' # (Required) The base directory of the TG
app code.
root_class = '' # (Required) The fully qualified Root
class name.
log_dir = r'' # (Optional) The log directory. Default =
code_dir.
# -- END USER EDIT SECTION
def SvcDoRun(self):
""" Called when the Windows Service runs. """
self.ReportServiceStatus(win32service.SERVICE_START_PENDING)
self.tg_init()
cherrypy.root = self.root()
self.ReportServiceStatus(win32service.SERVICE_RUNNING)
cherrypy.server.start()
def SvcStop(self):
"""Called when Windows receives a service stop request."""
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
cherrypy.server.stop()
self.ReportServiceStatus(win32service.SERVICE_STOPPED)
def tg_init(self):
""" Checks for the required data and initializes the
application. """
if TGWindowsService.code_dir:
os.chdir(TGWindowsService.code_dir)
sys.path.append(TGWindowsService.code_dir)
# Redirect stdout and stderr to avoid buffer crashes.
sys.stdout = open(join(TGWindowsService.log_dir,
'stdout.log'),'a')
sys.stderr = open(join(TGWindowsService.log_dir,
'stderr.log'),'a')
else:
raise ValueError("""The code directory setting is missing.
The Windows Service will not run
without this setting.""")
if not TGWindowsService.root_class:
raise ValueError("""The fully qualified root class name must
be provided.""")
if not TGWindowsService.log_dir:
TGWindowsService.log_dir = '.'
if exists(join(TGWindowsService.code_dir, "setup.py")):
cherrypy.config.update(file="dev.cfg")
else:
cherrypy.config.update(file="prod.cfg")
# Set environment to production to disable auto-reload.
cherrypy.config.update({'global': {'server.environment':
'production'},})
# Parse out the root class information and set it to self.root
full_class_name = TGWindowsService.root_class
last_mark = full_class_name.rfind('.')
if (last_mark < 1) or (last_mark + 1) == len(full_class_name):
raise ValueError("""The user-defined class name is invalid.
Please make sure to include a fully
qualified class name for the root_class
value (e.g. wiki20.controllers.Root).""")
package_name = full_class_name[:last_mark]
class_name = full_class_name[last_mark+1:]
exec('from %s import %s as Root' % (package_name, class_name))
self.root = Root
if __name__ == '__main__':
# The following are the most common command-line arguments that are
used
# with this module:
# service.py install (Installs the service with manual startup)
# service.py --startup auto install (Installs the service with
auto startup)
# service.py start (Starts the service)
# service.py stop (Stops the service)
# service.py remove (Removes the service)
#
# For a full list of arguments, simply type "service.py".
win32serviceutil.HandleCommandLine(TGWindowsService)