Django

Code

root/django/trunk/django/core/servers/fastcgi.py

Revision 7800, 6.1 kB (checked in by mtredinnick, 2 months ago)

Fixed #6994 -- For fastcgi, set a more sensible default umask.
Also allow the umask value to be customised. Thanks, Antonis Christofides.

  • Property svn:eol-style set to native
Line 
1 """
2 FastCGI (or SCGI, or AJP1.3 ...) server that implements the WSGI protocol.
3
4 Uses the flup python package: http://www.saddi.com/software/flup/
5
6 This is a adaptation of the flup package to add FastCGI server support
7 to run Django apps from Web servers that support the FastCGI protocol.
8 This module can be run standalone or from the django-admin / manage.py
9 scripts using the "runfcgi" directive.
10
11 Run with the extra option "help" for a list of additional options you can
12 pass to this server.
13 """
14
15 import sys, os
16
17 __version__ = "0.1"
18 __all__ = ["runfastcgi"]
19
20 FASTCGI_HELP = r"""
21   Run this project as a fastcgi (or some other protocol supported
22   by flup) application. To do this, the flup package from
23   http://www.saddi.com/software/flup/ is required.
24
25    runfcgi [options] [fcgi settings]
26
27 Optional Fcgi settings: (setting=value)
28   protocol=PROTOCOL    fcgi, scgi, ajp, ... (default fcgi)
29   host=HOSTNAME        hostname to listen on..
30   port=PORTNUM         port to listen on.
31   socket=FILE          UNIX socket to listen on.
32   method=IMPL          prefork or threaded (default prefork)
33   maxrequests=NUMBER   number of requests a child handles before it is
34                        killed and a new child is forked (0 = no limit).
35   maxspare=NUMBER      max number of spare processes / threads
36   minspare=NUMBER      min number of spare processes / threads.
37   maxchildren=NUMBER   hard limit number of processes / threads
38   daemonize=BOOL       whether to detach from terminal.
39   pidfile=FILE         write the spawned process-id to this file.
40   workdir=DIRECTORY    change to this directory when daemonizing.
41   outlog=FILE          write stdout to this file.
42   errlog=FILE          write stderr to this file.
43   umask=UMASK          umask to use when daemonizing (default 022).
44
45 Examples:
46   Run a "standard" fastcgi process on a file-descriptor
47   (for webservers which spawn your processes for you)
48     $ manage.py runfcgi method=threaded
49
50   Run a scgi server on a TCP host/port
51     $ manage.py runfcgi protocol=scgi method=prefork host=127.0.0.1 port=8025
52
53   Run a fastcgi server on a UNIX domain socket (posix platforms only)
54     $ manage.py runfcgi method=prefork socket=/tmp/fcgi.sock
55
56   Run a fastCGI as a daemon and write the spawned PID in a file
57     $ manage.py runfcgi socket=/tmp/fcgi.sock method=prefork \
58         daemonize=true pidfile=/var/run/django-fcgi.pid
59
60 """
61
62 FASTCGI_OPTIONS = {
63     'protocol': 'fcgi',
64     'host': None,
65     'port': None,
66     'socket': None,
67     'method': 'fork',
68     'daemonize': None,
69     'workdir': '/',
70     'pidfile': None,
71     'maxspare': 5,
72     'minspare': 2,
73     'maxchildren': 50,
74     'maxrequests': 0,
75     'outlog': None,
76     'errlog': None,
77     'umask': None,
78 }
79
80 def fastcgi_help(message=None):
81     print FASTCGI_HELP
82     if message:
83         print message
84     return False
85
86 def runfastcgi(argset=[], **kwargs):
87     options = FASTCGI_OPTIONS.copy()
88     options.update(kwargs)
89     for x in argset:
90         if "=" in x:
91             k, v = x.split('=', 1)
92         else:
93             k, v = x, True
94         options[k.lower()] = v
95
96     if "help" in options:
97         return fastcgi_help()
98
99     try:
100         import flup
101     except ImportError, e:
102         print >> sys.stderr, "ERROR: %s" % e
103         print >> sys.stderr, "  Unable to load the flup package.  In order to run django"
104         print >> sys.stderr, "  as a FastCGI application, you will need to get flup from"
105         print >> sys.stderr, "  http://www.saddi.com/software/flup/   If you've already"
106         print >> sys.stderr, "  installed flup, then make sure you have it in your PYTHONPATH."
107         return False
108
109     flup_module = 'server.' + options['protocol']
110
111     if options['method'] in ('prefork', 'fork'):
112         wsgi_opts = {
113             'maxSpare': int(options["maxspare"]),
114             'minSpare': int(options["minspare"]),
115             'maxChildren': int(options["maxchildren"]),
116             'maxRequests': int(options["maxrequests"]),
117         }
118         flup_module += '_fork'
119     elif options['method'] in ('thread', 'threaded'):
120         wsgi_opts = {
121             'maxSpare': int(options["maxspare"]),
122             'minSpare': int(options["minspare"]),
123             'maxThreads': int(options["maxchildren"]),
124         }
125     else:
126         return fastcgi_help("ERROR: Implementation must be one of prefork or thread.")
127
128     wsgi_opts['debug'] = False # Turn off flup tracebacks
129
130     try:
131         WSGIServer = getattr(__import__('flup.' + flup_module, '', '', flup_module), 'WSGIServer')
132     except:
133         print "Can't import flup." + flup_module
134         return False
135
136     # Prep up and go
137     from django.core.handlers.wsgi import WSGIHandler
138
139     if options["host"] and options["port"] and not options["socket"]:
140         wsgi_opts['bindAddress'] = (options["host"], int(options["port"]))
141     elif options["socket"] and not options["host"] and not options["port"]:
142         wsgi_opts['bindAddress'] = options["socket"]
143     elif not options["socket"] and not options["host"] and not options["port"]:
144         wsgi_opts['bindAddress'] = None
145     else:
146         return fastcgi_help("Invalid combination of host, port, socket.")
147
148     if options["daemonize"] is None:
149         # Default to daemonizing if we're running on a socket/named pipe.
150         daemonize = (wsgi_opts['bindAddress'] is not None)
151     else:
152         if options["daemonize"].lower() in ('true', 'yes', 't'):
153             daemonize = True
154         elif options["daemonize"].lower() in ('false', 'no', 'f'):
155             daemonize = False
156         else:
157             return fastcgi_help("ERROR: Invalid option for daemonize parameter.")
158
159     daemon_kwargs = {}
160     if options['outlog']:
161         daemon_kwargs['out_log'] = options['outlog']
162     if options['errlog']:
163         daemon_kwargs['err_log'] = options['errlog']
164     if options['umask']:
165         daemon_kwargs['umask'] = int(options['umask'])
166
167     if daemonize:
168         from django.utils.daemonize import become_daemon
169         become_daemon(our_home_dir=options["workdir"], **daemon_kwargs)
170
171     if options["pidfile"]:
172         fp = open(options["pidfile"], "w")
173         fp.write("%d\n" % os.getpid())
174         fp.close()
175
176     WSGIServer(WSGIHandler(), **wsgi_opts).run()
177
178 if __name__ == '__main__':
179     runfastcgi(sys.argv[1:])
Note: See TracBrowser for help on using the browser.