Opened 17 years ago

Closed 17 years ago

#3003 closed enhancement (duplicate)

Support for AJP server in manage.py

Reported by: Henrik Vendelbo <info@…> Owned by: Adrian Holovaty
Component: Core (Management commands) Version: dev
Severity: normal Keywords: ajp
Cc: Triage Stage: Unreviewed
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

With the latest Apache HTTPd 2.2 the Ajp 1.3 protocol is supported as part of the new proxy support. This means that multiple backends can be balanced using standard Apache functionality. Flup already supports Ajp, so it should be a very minor task to add the support. I believe I have a working patch. The only thing I haven't looked at is automatic restarting of the Django process like the FastCGI implementation.

for django.core.management

after def runfcgi(args):

def runajp(args):

"Runs this project as an AJP 1.3 application. Requires flup."
from django.conf import settings
from django.utils import translation
# Activate the current language, because it won't get activated later.
try:

translation.activate(settings.LANGUAGE_CODE)

except AttributeError:

pass

from django.core.servers.ajp import runajp
runajp(args)

runajp.args = '[various KEY=val options, use runajp help for help]'

after 'runfcgi'

'runajp': runajp,

after 'runfcgi' elfi

elif action == 'runajp':

new django.core.servers.ajp

"""
AJP 1.3 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 AJP 1.3 server support
to run Django apps from Web servers that support the AJP 1.3 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 = runajp

AJP_HELP = r"""runajp:

Run this project as an ajp application. To do this, the
flup package from http://www.saddi.com/software/flup/ is
required.

Usage:

django-admin.py runajp --settings=yourproject.settings [ajp settings]
manage.py runajp [ajp settings]

Optional Ajp13 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" ajp process on a file-descriptor
(for webservers which spawn your processes for you)

$ manage.py runajp method=threaded

Run an ajp server on a TCP host/port

$ manage.py runfcgi method=prefork host=127.0.0.1 port=8025

Run a ajp server on a UNIX domain socket (posix platforms only)

$ manage.py runfcgi method=prefork socket=/tmp/ajp.sock

Run a ajp as a daemon and write the spawned PID in a file

$ manage.py runfcgi socket=/tmp/ajp.sock method=prefork \

daemonize=true pidfile=/var/run/django-ajp.pid

"""

AJP_OPTIONS = {

'host': None,
'port': None,
'socket': None,
'method': 'fork',
'daemonize': None,
'workdir': '/',
'pidfile': None,
'maxspare': 5,
'minspare': 2,
'maxchildren': 50,

}

def ajp_help(message=None):

print AJP_HELP
if message:

print message

return False

def runajp(argset=[], kwargs):

options = AJP_OPTIONS.copy()
options.update(kwargs)
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 ajp_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 ajp 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 optionsmethod in ('prefork', 'fork'):

from flup.server.ajp_fork import WSGIServer
wsgi_opts = {

'maxSpare': int(optionsmaxspare),
'minSpare': int(optionsminspare),
'maxChildren': int(optionsmaxchildren),

}

elif optionsmethod in ('thread', 'threaded'):

from flup.server.ajp import WSGIServer
wsgi_opts = {}

else:

return ajp_help("ERROR: Implementation must be one of prefork or thread.")

# Prep up and go
from django.core.handlers.wsgi import WSGIHandler

if optionshost and optionsport and not optionssocket:

wsgi_optsbindAddress = (optionshost, int(optionsport))

elif optionssocket and not optionshost and not optionsport:

wsgi_optsbindAddress = optionssocket

elif not optionssocket and not optionshost and not optionsport:

wsgi_optsbindAddress = None

else:

return ajp_help("Invalid combination of host, port, socket.")

if optionsdaemonize is None:

# Default to daemonizing if we're running on a socket/named pipe.
daemonize = (wsgi_optsbindAddress is not None)

else:

if optionsdaemonize.lower() in ('true', 'yes', 't'):

daemonize = True

elif optionsdaemonize.lower() in ('false', 'no', 'f'):

daemonize = False

else:

return ajp_help("ERROR: Invalid option for daemonize parameter.")

if daemonize:

from django.utils.daemonize import become_daemon
become_daemon(our_home_dir=optionsworkdir)

if optionspidfile:

fp = open(optionspidfile, "w")
fp.write("%d\n" % os.getpid())
fp.close()

WSGIServer(WSGIHandler(), wsgi_opts).run()

if name == 'main':

runajp(sys.argv[1:])

Change History (1)

comment:1 by Simon G. <dev@…>, 17 years ago

Has patch: set
Keywords: ajp added
Resolution: duplicate
Status: newclosed

#3047 does something similar and is more generic.

Note: See TracTickets for help on using tickets.
Back to Top