Django

Code

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

Revision 10345, 6.2 kB (checked in by jacob, 3 months ago)

Fixed #8895: expose the debug setting to fastcgi. Thanks, paulegan.

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