2006-06-20 13:24:19 +08:00
|
|
|
"""
|
2007-04-01 15:30:27 +08:00
|
|
|
FastCGI (or SCGI, or AJP1.3 ...) server that implements the WSGI protocol.
|
2006-06-20 13:24:19 +08:00
|
|
|
|
|
|
|
Uses the flup python package: http://www.saddi.com/software/flup/
|
|
|
|
|
|
|
|
This is a adaptation of the flup package to add FastCGI server support
|
|
|
|
to run Django apps from Web servers that support the FastCGI protocol.
|
|
|
|
This module can be run standalone or from the django-admin / manage.py
|
|
|
|
scripts using the "runfcgi" directive.
|
|
|
|
|
|
|
|
Run with the extra option "help" for a list of additional options you can
|
|
|
|
pass to this server.
|
|
|
|
"""
|
|
|
|
|
|
|
|
import sys, os
|
|
|
|
|
|
|
|
__version__ = "0.1"
|
|
|
|
__all__ = ["runfastcgi"]
|
|
|
|
|
2007-09-10 05:57:59 +08:00
|
|
|
FASTCGI_HELP = r"""
|
2007-04-01 15:30:27 +08:00
|
|
|
Run this project as a fastcgi (or some other protocol supported
|
|
|
|
by flup) application. To do this, the flup package from
|
|
|
|
http://www.saddi.com/software/flup/ is required.
|
2006-06-20 13:24:19 +08:00
|
|
|
|
2007-09-10 05:57:59 +08:00
|
|
|
runfcgi [options] [fcgi settings]
|
2006-06-20 13:24:19 +08:00
|
|
|
|
|
|
|
Optional Fcgi settings: (setting=value)
|
2007-04-01 15:30:27 +08:00
|
|
|
protocol=PROTOCOL fcgi, scgi, ajp, ... (default fcgi)
|
2006-06-20 13:24:19 +08:00
|
|
|
host=HOSTNAME hostname to listen on..
|
|
|
|
port=PORTNUM port to listen on.
|
|
|
|
socket=FILE UNIX socket to listen on.
|
|
|
|
method=IMPL prefork or threaded (default prefork)
|
2006-10-31 20:27:55 +08:00
|
|
|
maxrequests=NUMBER number of requests a child handles before it is
|
|
|
|
killed and a new child is forked (0 = no limit).
|
2006-11-07 10:01:16 +08:00
|
|
|
maxspare=NUMBER max number of spare processes / threads
|
|
|
|
minspare=NUMBER min number of spare processes / threads.
|
|
|
|
maxchildren=NUMBER hard limit number of processes / threads
|
2006-06-20 13:24:19 +08:00
|
|
|
daemonize=BOOL whether to detach from terminal.
|
|
|
|
pidfile=FILE write the spawned process-id to this file.
|
|
|
|
workdir=DIRECTORY change to this directory when daemonizing
|
|
|
|
|
|
|
|
Examples:
|
|
|
|
Run a "standard" fastcgi process on a file-descriptor
|
|
|
|
(for webservers which spawn your processes for you)
|
|
|
|
$ manage.py runfcgi method=threaded
|
|
|
|
|
2007-04-01 15:30:27 +08:00
|
|
|
Run a scgi server on a TCP host/port
|
|
|
|
$ manage.py runfcgi protocol=scgi method=prefork host=127.0.0.1 port=8025
|
2006-06-20 13:24:19 +08:00
|
|
|
|
|
|
|
Run a fastcgi server on a UNIX domain socket (posix platforms only)
|
|
|
|
$ manage.py runfcgi method=prefork socket=/tmp/fcgi.sock
|
|
|
|
|
|
|
|
Run a fastCGI as a daemon and write the spawned PID in a file
|
|
|
|
$ manage.py runfcgi socket=/tmp/fcgi.sock method=prefork \
|
|
|
|
daemonize=true pidfile=/var/run/django-fcgi.pid
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
FASTCGI_OPTIONS = {
|
2007-04-01 15:30:27 +08:00
|
|
|
'protocol': 'fcgi',
|
2006-06-20 13:24:19 +08:00
|
|
|
'host': None,
|
|
|
|
'port': None,
|
|
|
|
'socket': None,
|
|
|
|
'method': 'fork',
|
|
|
|
'daemonize': None,
|
|
|
|
'workdir': '/',
|
|
|
|
'pidfile': None,
|
|
|
|
'maxspare': 5,
|
|
|
|
'minspare': 2,
|
|
|
|
'maxchildren': 50,
|
2006-10-31 20:27:55 +08:00
|
|
|
'maxrequests': 0,
|
2006-06-20 13:24:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
def fastcgi_help(message=None):
|
|
|
|
print FASTCGI_HELP
|
|
|
|
if message:
|
|
|
|
print message
|
|
|
|
return False
|
|
|
|
|
2006-09-21 21:45:24 +08:00
|
|
|
def runfastcgi(argset=[], **kwargs):
|
2006-06-20 13:24:19 +08:00
|
|
|
options = FASTCGI_OPTIONS.copy()
|
2006-09-14 23:37:11 +08:00
|
|
|
options.update(kwargs)
|
2006-06-20 13:24:19 +08:00
|
|
|
for x in argset:
|
|
|
|
if "=" in x:
|
|
|
|
k, v = x.split('=', 1)
|
|
|
|
else:
|
|
|
|
k, v = x, True
|
|
|
|
options[k.lower()] = v
|
|
|
|
|
|
|
|
if "help" in options:
|
|
|
|
return fastcgi_help()
|
|
|
|
|
|
|
|
try:
|
|
|
|
import flup
|
|
|
|
except ImportError, e:
|
|
|
|
print >> sys.stderr, "ERROR: %s" % e
|
|
|
|
print >> sys.stderr, " Unable to load the flup package. In order to run django"
|
|
|
|
print >> sys.stderr, " as a FastCGI application, you will need to get flup from"
|
|
|
|
print >> sys.stderr, " http://www.saddi.com/software/flup/ If you've already"
|
|
|
|
print >> sys.stderr, " installed flup, then make sure you have it in your PYTHONPATH."
|
|
|
|
return False
|
|
|
|
|
2007-04-01 15:30:27 +08:00
|
|
|
flup_module = 'server.' + options['protocol']
|
|
|
|
|
2006-06-20 13:24:19 +08:00
|
|
|
if options['method'] in ('prefork', 'fork'):
|
|
|
|
wsgi_opts = {
|
|
|
|
'maxSpare': int(options["maxspare"]),
|
|
|
|
'minSpare': int(options["minspare"]),
|
|
|
|
'maxChildren': int(options["maxchildren"]),
|
2006-10-31 20:27:55 +08:00
|
|
|
'maxRequests': int(options["maxrequests"]),
|
2006-06-20 13:24:19 +08:00
|
|
|
}
|
2007-04-01 15:30:27 +08:00
|
|
|
flup_module += '_fork'
|
2006-06-20 13:24:19 +08:00
|
|
|
elif options['method'] in ('thread', 'threaded'):
|
2006-11-07 10:01:16 +08:00
|
|
|
wsgi_opts = {
|
|
|
|
'maxSpare': int(options["maxspare"]),
|
|
|
|
'minSpare': int(options["minspare"]),
|
|
|
|
'maxThreads': int(options["maxchildren"]),
|
|
|
|
}
|
2006-06-20 13:24:19 +08:00
|
|
|
else:
|
|
|
|
return fastcgi_help("ERROR: Implementation must be one of prefork or thread.")
|
|
|
|
|
2006-12-07 11:04:22 +08:00
|
|
|
wsgi_opts['debug'] = False # Turn off flup tracebacks
|
|
|
|
|
2007-04-01 15:30:27 +08:00
|
|
|
try:
|
|
|
|
WSGIServer = getattr(__import__('flup.' + flup_module, '', '', flup_module), 'WSGIServer')
|
|
|
|
except:
|
|
|
|
print "Can't import flup." + flup_module
|
|
|
|
return False
|
|
|
|
|
2006-06-20 13:24:19 +08:00
|
|
|
# Prep up and go
|
|
|
|
from django.core.handlers.wsgi import WSGIHandler
|
|
|
|
|
|
|
|
if options["host"] and options["port"] and not options["socket"]:
|
|
|
|
wsgi_opts['bindAddress'] = (options["host"], int(options["port"]))
|
|
|
|
elif options["socket"] and not options["host"] and not options["port"]:
|
|
|
|
wsgi_opts['bindAddress'] = options["socket"]
|
|
|
|
elif not options["socket"] and not options["host"] and not options["port"]:
|
|
|
|
wsgi_opts['bindAddress'] = None
|
|
|
|
else:
|
|
|
|
return fastcgi_help("Invalid combination of host, port, socket.")
|
|
|
|
|
|
|
|
if options["daemonize"] is None:
|
|
|
|
# Default to daemonizing if we're running on a socket/named pipe.
|
|
|
|
daemonize = (wsgi_opts['bindAddress'] is not None)
|
|
|
|
else:
|
|
|
|
if options["daemonize"].lower() in ('true', 'yes', 't'):
|
|
|
|
daemonize = True
|
|
|
|
elif options["daemonize"].lower() in ('false', 'no', 'f'):
|
|
|
|
daemonize = False
|
|
|
|
else:
|
|
|
|
return fastcgi_help("ERROR: Invalid option for daemonize parameter.")
|
|
|
|
|
|
|
|
if daemonize:
|
|
|
|
from django.utils.daemonize import become_daemon
|
|
|
|
become_daemon(our_home_dir=options["workdir"])
|
|
|
|
|
|
|
|
if options["pidfile"]:
|
|
|
|
fp = open(options["pidfile"], "w")
|
|
|
|
fp.write("%d\n" % os.getpid())
|
|
|
|
fp.close()
|
|
|
|
|
|
|
|
WSGIServer(WSGIHandler(), **wsgi_opts).run()
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
runfastcgi(sys.argv[1:])
|