PylonsHQ.

Layout: Fixed-width

How to run Pylons as a Windows service

Skip to end of metadata
Go to start of metadata
Unknown macro: {metadata-list}
Name How to run Pylons as a Windows service
Space Pylons CookBook
Section  
Page How to run Pylons as a Windows service
Version 1.0
Status Draft
Curator Graham Higgins
Reviewed False
Author(s)  

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:

  1. you already have a pylons application installed and can be run from the usual command line (paster serve your.ini)
  2. 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
  1. 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.
  2. Once you have edited winsrvice secion in the ini file, install the service with the following command line:
    • WindowsService.py install
  3. Run the service
    • WindowsService.py start
  4. 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

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Apr 21, 2008

    James Su says:

    Thanks! But I don't like "guess", so modified your code to read certain ini file...

    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.

  2. Aug 23, 2009

    Tibor Arpas says:

    This work's very well. I just didn't like the copy & paste approach for ever...

    This work's very well. I just didn't like the copy & paste approach for every project/every deployment. So I tried to generalize the script and give it the config file parameter. I found out it's not completely straightforward. So I've put up my general script for the others to use. The module is called wsgisvc (http://pypi.python.org/pypi/wsgisvc).

    "wsgisvc" replaces "WindowsService.py" and allows you to specify any configuration file you like with the -c option.

    wsgisvc -c development.ini install
    wsgisvc -c development.ini start
    

    etc.. Also the [winservice] options are altered so check out the documentation for wsgisvc if you need a general script.

     


Powered by Pylons - Contact Administrators