mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +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:
		
							
								
								
									
										1
									
								
								AUTHORS
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								AUTHORS
									
									
									
									
									
								
							| @@ -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 | ||||
|   | ||||
| @@ -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 @@ DEFAULT_ACTION_MAPPING = { | ||||
|     '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
									
									
									
									
									
										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 | ||||
		Reference in New Issue
	
	Block a user