| Name |
Space |
Section |
Page |
Version |
Status |
Curator |
Reviewed |
Author(s) |
| How to run Pylons as a Windows service |
Pylons CookBook |
|
How to run Pylons as a Windows service |
1.0 |
Draft |
Graham Higgins |
False |
|
How to run Pylons as a Windows service
This tutorial will demonstrate how to launch a pylons app as a windows service. Most of the code is taken directly from a CherryPy
example I found while trying to figure out how to do this for myself.
The tutorial assumes that:
- you already have a pylons application installed and can be run from the usual command line (paster serve your.ini)
- you have Marks Hammond's pywin32
installed
- If you are running ActiveState's python distribution then it's already installed
1) copy the code below
First you will want to copy the code below to the same folder as your application's ini file as WindowsService.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94 | """
The most basic (working) Windows service possible.
Requires Mark Hammond's pywin32 package.
Most of the code was taken from a CherryPy 2.2 example of how to set up a service
"""
import pkg_resources
import win32serviceutil
from paste.script.serve import ServeCommand as Server
import os, sys
import ConfigParser
import win32service
import win32event
class DefaultSettings(object):
def __init__(self):
if os.path.dirname(__file__):
os.chdir(os.path.dirname(__file__))
# find the ini file
self.ini = [x for x in os.listdir('.')
if os.path.splitext(x)[1].lower().endswith('ini')]
# create a config parser opject and populate it with the ini file
c = ConfigParser.SafeConfigParser()
c.read(self.ini[0])
self.c = c
def getDefaults(self):
'''
Check for and get the default settings
'''
if (
(not self.c.has_section('winservice')) or
(not self.c.has_option('winservice', 'service_name')) or
(not self.c.has_option('winservice', 'service_display_name')) or
(not self.c.has_option('winservice', 'service_description'))
):
print 'setting defaults'
self.setDefaults()
service_name = self.c.get('winservice', 'service_name')
service_display_name = self.c.get('winservice', 'service_display_name')
service_description = self.c.get('winservice', 'service_description')
iniFile = self.ini[0]
return service_name, service_display_name, service_description, iniFile
def setDefaults(self):
'''
set and add the default setting to the ini file
'''
if not self.c.has_section('winservice'):
self.c.add_section('winservice')
self.c.set('winservice', 'service_name', 'WSCGIService')
self.c.set('winservice', 'service_display_name', 'WSCGI windows service')
self.c.set('winservice', 'service_description', 'WSCGI windows service')
cfg = file(self.ini[0], 'wr')
self.c.write(cfg)
cfg.close()
print '''
you must set the winservice section service_name, service_display_name,
and service_description options to define the service
in the %s file
''' % self.ini[0]
sys.exit()
class MyService(win32serviceutil.ServiceFramework):
"""NT Service."""
d = DefaultSettings()
service_name, service_display_name, service_description, iniFile = d.getDefaults()
_svc_name_ = service_name
_svc_display_name_ = service_display_name
_svc_description_ = service_description
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
# create an event that SvcDoRun can wait on and SvcStop
# can set.
self.stop_event = win32event.CreateEvent(None, 0, 0, None)
def SvcDoRun(self):
os.chdir(os.path.dirname(__file__))
s = Server(None)
s.run([self.iniFile])
win32event.WaitForSingleObject(self.stop_event, win32event.INFINITE)
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
#win32event.SetEvent(self.stop_event)
self.ReportServiceStatus(win32service.SERVICE_STOPPED)
sys.exit()
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(MyService)
|
2) Set up the Windows service
All windows services need to have unique parameters defined so that windows can identify them, such as:
- service_name
- This is the short name that windows uses to manage the service and is used by the net start comment This name must be unique
- service_display_name
- This what is displayed in the list of services as the service name. Typically this is a little more descriptive then the service_name, but they may be the same
- service_description
- this is a short description of what the service does and is displayed along side the service name in the list of services. This is optional and may be left blank
- To setup the Windows service simply run the WindowsService.py program. The program will search for your ini within the directory it is run from, and search for the appropriate "winservice" section. If you have created multiple ini files WindowsService.py simply picks the first one it finds. If the "winservice" section is not found it will be added with the default settings. If this is the first time you've run WindowsService.py I would suggest editing the new section with values which make sence to you.
- Once you have edited winsrvice secion in the ini file, install the service with the following command line:
- WindowsService.py install
- Run the service
- Running WindowsService.py without any commandline arguments will display a nice help screen with service control options
3) What if something goes wrong?
If something goes wrong and the service does not start take a look at the Application log under the event viewer, that should help you debug what might have gone wrong
If you have any questions, feel free to ask them at: http://groups.google.com/group/pylons-discuss
Jose
Thanks!
But I don't like "guess", so modified your code to read certain ini file:
#if os.path.dirname(__file__): #os.chdir(os.path.dirname(__file__)) # find the ini file #self.ini = [x for x in os.listdir('.') #if os.path.splitext(x)[1].lower().endswith('ini')] self.ini = [os.path.join(os.environ['WINDIR'], 'MyApp.ini')]Then you can rename your development.ini or product.ini to MyApp.ini as you like.