mirror of
https://github.com/django/django.git
synced 2024-12-22 17:16:24 +00:00
Added django/core/servers/fastcgi.py and manage.py 'runfcgi' option. Thanks, jcrasta@gmail.com
git-svn-id: http://code.djangoproject.com/svn/django/trunk@3174 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
a4b11826a7
commit
32228d2031
1
AUTHORS
1
AUTHORS
@ -65,6 +65,7 @@ answer newbie questions, and generally made Django that much better:
|
|||||||
Kieran Holland <http://www.kieranholland.com>
|
Kieran Holland <http://www.kieranholland.com>
|
||||||
Robert Rock Howard <http://djangomojo.com/>
|
Robert Rock Howard <http://djangomojo.com/>
|
||||||
Jason Huggins <http://www.jrandolph.com/blog/>
|
Jason Huggins <http://www.jrandolph.com/blog/>
|
||||||
|
jcrasta@gmail.com
|
||||||
Michael Josephson <http://www.sdjournal.com/>
|
Michael Josephson <http://www.sdjournal.com/>
|
||||||
jpellerin@gmail.com
|
jpellerin@gmail.com
|
||||||
junzhang.jn@gmail.com
|
junzhang.jn@gmail.com
|
||||||
|
@ -1081,6 +1081,12 @@ def dbshell():
|
|||||||
runshell()
|
runshell()
|
||||||
dbshell.args = ""
|
dbshell.args = ""
|
||||||
|
|
||||||
|
def runfcgi(args):
|
||||||
|
"""Run this project as a FastCGI application. requires flup."""
|
||||||
|
from django.core.servers.fastcgi import runfastcgi
|
||||||
|
runfastcgi(args)
|
||||||
|
runfcgi.args = '[various KEY=val options, use `runfcgi help` for help]'
|
||||||
|
|
||||||
# Utilities for command-line script
|
# Utilities for command-line script
|
||||||
|
|
||||||
DEFAULT_ACTION_MAPPING = {
|
DEFAULT_ACTION_MAPPING = {
|
||||||
@ -1091,6 +1097,7 @@ DEFAULT_ACTION_MAPPING = {
|
|||||||
'inspectdb': inspectdb,
|
'inspectdb': inspectdb,
|
||||||
'install': install,
|
'install': install,
|
||||||
'reset': reset,
|
'reset': reset,
|
||||||
|
'runfcgi': runfcgi,
|
||||||
'runserver': runserver,
|
'runserver': runserver,
|
||||||
'shell': run_shell,
|
'shell': run_shell,
|
||||||
'sql': get_sql_create,
|
'sql': get_sql_create,
|
||||||
@ -1210,6 +1217,8 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
addr, port = '', args[1]
|
addr, port = '', args[1]
|
||||||
action_mapping[action](addr, port)
|
action_mapping[action](addr, port)
|
||||||
|
elif action == 'runfcgi':
|
||||||
|
action_mapping[action](args[1:])
|
||||||
else:
|
else:
|
||||||
from django.db import models
|
from django.db import models
|
||||||
try:
|
try:
|
||||||
|
147
django/core/servers/fastcgi.py
Normal file
147
django/core/servers/fastcgi.py
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
"""
|
||||||
|
FastCGI server that implements the WSGI protocol.
|
||||||
|
|
||||||
|
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"]
|
||||||
|
|
||||||
|
FASTCGI_HELP = r"""runfcgi:
|
||||||
|
Run this project as a fastcgi application. To do this, the
|
||||||
|
flup package from http://www.saddi.com/software/flup/ is
|
||||||
|
required.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
django-admin.py runfcgi --settings=yourproject.settings [fcgi settings]
|
||||||
|
manage.py runfcgi [fcgi settings]
|
||||||
|
|
||||||
|
Optional Fcgi settings: (setting=value)
|
||||||
|
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)
|
||||||
|
maxspare=NUMBER max number of spare processes to keep running.
|
||||||
|
minspare=NUMBER min number of spare processes to prefork.
|
||||||
|
maxchildren=NUMBER hard limit number of processes in prefork mode.
|
||||||
|
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
|
||||||
|
|
||||||
|
Run a fastcgi server on a TCP host/port
|
||||||
|
$ manage.py runfcgi method=prefork host=127.0.0.1 port=8025
|
||||||
|
|
||||||
|
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 = {
|
||||||
|
'host': None,
|
||||||
|
'port': None,
|
||||||
|
'socket': None,
|
||||||
|
'method': 'fork',
|
||||||
|
'daemonize': None,
|
||||||
|
'workdir': '/',
|
||||||
|
'pidfile': None,
|
||||||
|
'maxspare': 5,
|
||||||
|
'minspare': 2,
|
||||||
|
'maxchildren': 50,
|
||||||
|
}
|
||||||
|
|
||||||
|
def fastcgi_help(message=None):
|
||||||
|
print FASTCGI_HELP
|
||||||
|
if message:
|
||||||
|
print message
|
||||||
|
return False
|
||||||
|
|
||||||
|
def runfastcgi(argset):
|
||||||
|
options = FASTCGI_OPTIONS.copy()
|
||||||
|
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
|
||||||
|
|
||||||
|
if options['method'] in ('prefork', 'fork'):
|
||||||
|
from flup.server.fcgi_fork import WSGIServer
|
||||||
|
wsgi_opts = {
|
||||||
|
'maxSpare': int(options["maxspare"]),
|
||||||
|
'minSpare': int(options["minspare"]),
|
||||||
|
'maxChildren': int(options["maxchildren"]),
|
||||||
|
}
|
||||||
|
elif options['method'] in ('thread', 'threaded'):
|
||||||
|
from flup.server.fcgi import WSGIServer
|
||||||
|
wsgi_opts = {}
|
||||||
|
else:
|
||||||
|
return fastcgi_help("ERROR: Implementation must be one of prefork or thread.")
|
||||||
|
|
||||||
|
# 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:])
|
55
django/utils/daemonize.py
Normal file
55
django/utils/daemonize.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if os.name == 'posix':
|
||||||
|
def become_daemon(our_home_dir='.', out_log='/dev/null', err_log='/dev/null'):
|
||||||
|
"Robustly turn into a UNIX daemon, running in our_home_dir."
|
||||||
|
# First fork
|
||||||
|
try:
|
||||||
|
if os.fork() > 0:
|
||||||
|
sys.exit(0) # kill off parent
|
||||||
|
except OSError, e:
|
||||||
|
sys.stderr.write("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror))
|
||||||
|
sys.exit(1)
|
||||||
|
os.setsid()
|
||||||
|
os.chdir(our_home_dir)
|
||||||
|
os.umask(0)
|
||||||
|
|
||||||
|
# Second fork
|
||||||
|
try:
|
||||||
|
if os.fork() > 0:
|
||||||
|
sys.exit(0)
|
||||||
|
except OSError, e:
|
||||||
|
sys.stderr.write("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
si = open('/dev/null', 'r')
|
||||||
|
so = open(out_log, 'a+', 0)
|
||||||
|
se = open(err_log, 'a+', 0)
|
||||||
|
os.dup2(si.fileno(), sys.stdin.fileno())
|
||||||
|
os.dup2(so.fileno(), sys.stdout.fileno())
|
||||||
|
os.dup2(se.fileno(), sys.stderr.fileno())
|
||||||
|
else:
|
||||||
|
def become_daemon(our_home_dir='.', out_log=None, err_log=None):
|
||||||
|
"""
|
||||||
|
If we're not running under a POSIX system, just simulate the daemon
|
||||||
|
mode by doing redirections and directory changing.
|
||||||
|
"""
|
||||||
|
os.chdir(our_home_dir)
|
||||||
|
os.umask(0)
|
||||||
|
sys.stdin.close()
|
||||||
|
sys.stdout.close()
|
||||||
|
sys.stderr.close()
|
||||||
|
if err_log:
|
||||||
|
sys.stderr = open(err_log, 'a', 0)
|
||||||
|
else:
|
||||||
|
sys.stderr = NullDevice()
|
||||||
|
if out_log:
|
||||||
|
sys.stdout = open(out_log, 'a', 0)
|
||||||
|
else:
|
||||||
|
sys.stdout = NullDevice()
|
||||||
|
|
||||||
|
class NullDevice:
|
||||||
|
"A writeable object that writes to nowhere -- like /dev/null."
|
||||||
|
def write(self, s):
|
||||||
|
pass
|
Loading…
Reference in New Issue
Block a user