Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

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
  • Loading branch information...
commit 32228d2031ac661305f219641cc1fc336cee1c2e 1 parent a4b1182
Adrian Holovaty adrianholovaty authored
1  AUTHORS
View
@@ -65,6 +65,7 @@ answer newbie questions, and generally made Django that much better:
Kieran Holland <http://www.kieranholland.com>
Robert Rock Howard <http://djangomojo.com/>
Jason Huggins <http://www.jrandolph.com/blog/>
+ jcrasta@gmail.com
Michael Josephson <http://www.sdjournal.com/>
jpellerin@gmail.com
junzhang.jn@gmail.com
9 django/core/management.py
View
@@ -1081,6 +1081,12 @@ def dbshell():
runshell()
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
DEFAULT_ACTION_MAPPING = {
@@ -1091,6 +1097,7 @@ def dbshell():
'inspectdb': inspectdb,
'install': install,
'reset': reset,
+ 'runfcgi': runfcgi,
'runserver': runserver,
'shell': run_shell,
'sql': get_sql_create,
@@ -1210,6 +1217,8 @@ def execute_from_command_line(action_mapping=DEFAULT_ACTION_MAPPING, argv=None):
except ValueError:
addr, port = '', args[1]
action_mapping[action](addr, port)
+ elif action == 'runfcgi':
+ action_mapping[action](args[1:])
else:
from django.db import models
try:
147 django/core/servers/fastcgi.py
View
@@ -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
View
@@ -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
Please sign in to comment.
Something went wrong with that request. Please try again.