Ticket #1736: django-fastcgi-new.diff

File django-fastcgi-new.diff, 8.3 KB (added by jcrasta@…, 9 years ago)

Updated django-management fastcgi patch as per suggestions, use patch -p0 in trunk

  • django/core/servers/fastcgi.py

     
     1"""
     2FastCGI server that implements the WSGI protocol.
     3
     4Uses the flup python package: http://www.saddi.com/software/flup/
     5
     6This is a adaptation of the flup package to add FastCGI server support
     7to run Django apps from web-servers which support the FastCGI protocol;
     8this module can be run stand-alone or from the django-admin / manage.py
     9scripts using the `runfcgi` directive.
     10
     11Run with the extra option "help" for a list of additional options you can
     12pass to this server.
     13"""
     14
     15import sys
     16
     17__version__ = "0.1"
     18__all__ = ["runfastcgi"]
     19
     20FASTCGI_HELP = r"""runfcgi:
     21  Run this project as a fastcgi application. To do this, the
     22  flup package from http://www.saddi.com/software/flup/ is
     23  required.
     24
     25Usage:
     26   django-admin.py runfcgi --setttings=yourproject.settings [fcgi settings]
     27   manage.py runfcgi [fcgi settings]
     28     
     29Optional Fcgi settings: (setting=value)
     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  maxspare=NUMBER      max number of spare processes to keep running.
     35  minspare=NUMBER      min number of spare processes to prefork.
     36  maxchildren=NUMBER   hard limit number of processes in prefork mode.
     37  daemonize=BOOL       whether to detach from terminal.
     38  pidfile=FILE         write the spawned process-id to this file.
     39  workdir=DIRECTORY    change to this directory when daemonizing
     40
     41Examples:
     42  Run a "standard" fastcgi process on a file-descriptor
     43  (for webservers which spawn your processes for you)
     44    $ manage.py runfcgi method=threaded
     45
     46  Run a fastcgi server on a TCP host/port
     47    $ manage.py runfcgi method=prefork host=127.0.0.1 port=8025
     48
     49  Run a fastcgi server on a UNIX domain socket (posix platforms only)
     50    $ manage.py runfcgi method=prefork socket=/tmp/fcgi.sock
     51
     52  Run a fastCGI as a daemon and write the spawned PID in a file
     53    $ manage.py runfcgi socket=/tmp/fcgi.sock method=prefork \
     54        daemonize=true pidfile=/var/run/django-fcgi.pid
     55 
     56"""
     57
     58FASTCGI_OPTIONS = {
     59    'host': None,
     60    'port': None,
     61    'socket': None,
     62    'method': 'fork',
     63    'daemonize': None,
     64    'workdir': '/',
     65    'pidfile': None,
     66    'maxspare': 5,
     67    'minspare': 2,
     68    'maxchildren': 50,
     69}
     70
     71def fastcgi_help(message = None):
     72    print FASTCGI_HELP
     73    if message:
     74        print message
     75    return False
     76
     77
     78def runfastcgi(argset):
     79    options = FASTCGI_OPTIONS.copy()
     80    for x in argset:
     81        if "=" in x:
     82            k, v = x.split('=', 1)
     83        else:
     84            k,v = x, True
     85        options[k.lower()] = v
     86
     87    if "help" in options:
     88        return fastcgi_help()
     89
     90    try:
     91        import flup
     92    except ImportError, e:
     93        print >> sys.stderr, "ERROR: %s" % e
     94        print >> sys.stderr, "  Unable to load the flup package.  In order to run django"
     95        print >> sys.stderr, "  as a FastCGI application, you will need to get flup from"
     96        print >> sys.stderr, "  http://www.saddi.com/software/flup/   If you have flup already"
     97        print >> sys.stderr, "  installed, then make sure you have it in your pythonpath."
     98        return False
     99       
     100    if options['method'] in ('prefork', 'fork'):
     101        from flup.server.fcgi_fork import WSGIServer
     102        wsgi_opts = dict(
     103            maxSpare = int(options["maxspare"]),
     104            minSpare = int(options["minspare"]),
     105            maxChildren = int(options["maxchildren"]),
     106        )
     107    elif options['method'] in ('thread', 'threaded'):
     108        from flup.server.fcgi import WSGIServer
     109        wsgi_opts = {}
     110    else:
     111        return fastcgi_help("ERROR: implementation must be one of prefork or thread")
     112
     113    # prep up and go
     114    from django.core.handlers.wsgi import WSGIHandler
     115
     116    if options["host"] and options["port"] and not options["socket"]:
     117        wsgi_opts['bindAddress'] = (options["host"], int(options["port"]))
     118    elif options["socket"] and not options["host"] and not options["port"]:
     119        wsgi_opts['bindAddress'] = options["socket"]
     120    elif not options["socket"] and not options["host"] and not options["port"]:
     121        wsgi_opts['bindAddress'] = None
     122    else:
     123        return fastcgi_help("invalid combination of host,port,socket.")
     124
     125    if options["daemonize"] is None:
     126        # default to daemonizing if we are running on a socket/named pipe
     127        daemonize = (wsgi_opts['bindAddress'] is not None)
     128    else:
     129        if options["daemonize"].lower() in ('true', 'yes', 't'):
     130            daemonize = True
     131        elif options["daemonize"].lower() in ('false', 'no', 'f'):
     132            daemonize = False
     133        else:
     134            return fastcgi_help("ERROR: invalid option for daemonize parameter")
     135   
     136    if daemonize:
     137        from django.utils.daemonize import become_daemon
     138        become_daemon(ourHomeDir=options["workdir"])
     139
     140    if options["pidfile"]:
     141        fp = open(options["pidfile"], "w")
     142        fp.write("%d\n" % os.getpid())
     143        fp.close()
     144
     145    WSGIServer(WSGIHandler(), **wsgi_opts).run()
     146
     147if __name__ == '__main__':
     148    runfastcgi(sys.argv[1:])
  • django/core/management.py

     
    10811081    runshell()
    10821082dbshell.args = ""
    10831083
     1084def runfcgi(args):
     1085    """Run this project as a FastCGI application. requires flup."""
     1086    from django.core.servers.fastcgi import runfastcgi
     1087    runfastcgi(args)
     1088runfcgi.args = '[various KEY=val options, use `runfcgi help` for help]'
     1089
    10841090# Utilities for command-line script
    10851091
    10861092DEFAULT_ACTION_MAPPING = {
     
    10911097    'inspectdb': inspectdb,
    10921098    'install': install,
    10931099    'reset': reset,
     1100    'runfcgi': runfcgi,
    10941101    'runserver': runserver,
    10951102    'shell': run_shell,
    10961103    'sql': get_sql_create,
     
    12101217            except ValueError:
    12111218                addr, port = '', args[1]
    12121219        action_mapping[action](addr, port)
     1220    elif action == 'runfcgi':
     1221        action_mapping[action](args[1:])
    12131222    else:
    12141223        from django.db import models
    12151224        try:
  • django/utils/daemonize.py

     
     1import os
     2import sys
     3
     4if os.name == 'posix':
     5
     6        def become_daemon(ourHomeDir='.',outLog='/dev/null',errLog='/dev/null'):
     7                """
     8                Robustly turn us into a UNIX daemon, running in ourHomeDir.
     9                Modelled after the original code of this module and some
     10                sample code from the net.
     11                """
     12
     13                # first fork
     14                try:
     15                        if os.fork() > 0:
     16                                sys.exit(0)     # kill off parent
     17                except OSError, e:
     18                        sys.stderr.write("fork #1 failed: (%d) %s\n" % (e.errno, e.strerror))
     19                        sys.exit(1)
     20                os.setsid()
     21                os.chdir(ourHomeDir)
     22                os.umask(0)
     23                # second fork
     24                try:
     25                        if os.fork() > 0:
     26                                sys.exit(0)
     27                except OSError, e:
     28                        sys.stderr.write("fork #2 failed: (%d) %s\n" % (e.errno, e.strerror))
     29                        sys.exit(1)
     30
     31                si = open('/dev/null', 'r')
     32                so = open(outLog, 'a+', 0)
     33                se = open(errLog, 'a+', 0)
     34                os.dup2(si.fileno(), sys.stdin.fileno())
     35                os.dup2(so.fileno(), sys.stdout.fileno())
     36                os.dup2(se.fileno(), sys.stderr.fileno())
     37
     38else:
     39
     40        def become_daemon(ourHomeDir='.',outLog=None,errLog=None):
     41                """
     42                If we are not running under a POSIX system, just simulate
     43                the daemon mode by doing redirections and directory changeing
     44                """
     45
     46                os.chdir(ourHomeDir)
     47                os.umask(0)
     48                sys.stdin.close()
     49                sys.stdout.close()
     50                sys.stderr.close()
     51                if errLog and outLog:
     52                        sys.stderr=open (errLog, 'a', 0)
     53                        sys.stdout=open (outLog, 'a', 0)
     54                elif errLog:
     55                        sys.stderr=open (errLog, 'a', 0)
     56                        sys.stdout=NullDevice ()
     57                elif outLog:
     58                        sys.stdout=open (outLog, 'a', 0)
     59                        sys.stderr=NullDevice ()
     60                else:
     61                        sys.stdout = NullDevice()
     62                        sys.stderr = NullDevice()
     63
     64        class NullDevice:
     65                """
     66                A substitute for stdout and stderr that writes to nowhere.
     67                This is a substitute for /dev/null
     68                """
     69       
     70                def write(self, s):
     71                        pass
Back to Top