Code

Opened 7 years ago

Closed 7 years ago

#3003 closed enhancement (duplicate)

Support for AJP server in manage.py

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

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:])

Attachments (0)

Change History (1)

comment:1 Changed 7 years ago by Simon G. <dev@…>

  • Has patch set
  • Keywords ajp added
  • Resolution set to duplicate
  • Status changed from new to closed

#3047 does something similar and is more generic.

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
as The resolution will be set. Next status will be 'closed'
The resolution will be deleted. Next status will be 'new'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.