# -*- mode: python; tab-width:8; py-indent-offset:4; indent-tabs-mode:nil -*-
#pylint: disable=C0301
#line length;
"""
Django process management.
Use this module to run a django app.
"""
import os
import socket
import subprocess
import sys
import base
import my_setproctitle
# XXX distinguish keyword parms in docs;
[docs]class Manager(base.ManagerBase):
"""
Django manager object.
:param host: the interface to listen on.
:type host: string
:param port: the port to listen on.
:type port: int
:param settings: name of the django settings module
:type settings: string
:param name: the program name
:type name: string
:param process_name: the string to diplay in 'ps'
:type process_name: string
"""
__implements__ = base.ManagerInterface
def __init__(self, host, port, settings, **kwargs):
name = kwargs.get("name", "DjangoApp")
process_name = kwargs.get("process_name", None)
super(Manager, self).__init__(name, process_name=process_name)
self.host = host
self.port = port
self.settings = settings
[docs] def health(self):
"""
Check the health of the django subprocess.
:raises: **base.WorkerError** if we cannot create a socket connection to app.
"""
try:
s__ = socket.create_connection((self.host, self.port))
s__.close()
except socket.error, ex:
raise base.WorkerError(ex)
[docs] def start(self, wait=True, timeout=10.0):
"""
Start the Django app in its own process.
:param wait: If true, call self.ready_wait() after starting the subprocess.
:param timeout: When calling ready_wait(), use this timeout value.
:type timeout: float, number of seconds
:raises: **base.WorkerError** if the worker hasn't started before timeout elapses.
"""
launch_prog = '\n'.join(
["""from servermgr import django_app;"""
"""django_app.Manager.launch(host="%s", port=%d, process_name="%s", settings="%s")"""
]) % (self.host, self.port, self.process_name, self.settings)
self.process = subprocess.Popen(["python", "-c", launch_prog])
if wait:
self.ready_wait(timeout=timeout)
@staticmethod
[docs] def launch(**kwargs):
"""
Launch a django app in a fresh python environment.
:param host: the fcgi listener interface
:param port: the fcgi listener port
:type port: int
:param process_name: the displayed program name;
:settings: the django settings module name;
"""
settings = kwargs.get("settings")
pname = kwargs.get("process_name", None)
if pname:
my_setproctitle.setproctitle(pname)
os.environ["DJANGO_SETTINGS_MODULE"] = settings
from django.core.management.commands import runfcgi
cmd = runfcgi.Command()
cmd.handle("host="+kwargs["host"],
"port="+str(kwargs["port"]),
"method=prefork",
"daemonize=False",
"maxchildren=2",
"maxspare=2")
[docs]def main():
"""main routine."""
import optparse
def get_module_directory(module_name):
"""Find the filesystem directory where a module lives."""
try:
__import__(module_name)
app_dir = os.path.dirname(sys.modules[module_name].__file__)
return app_dir
except ImportError, ex:
print >> sys.stderr, ex
print >> sys.stderr, "Cannot find settings module " + settings
sys.exit(1)
default_host = "localhost"
parser = optparse.OptionParser(usage="usage: %prog [options]")
parser.add_option("-H", "--host", action="store", dest="host", help="django app host")
parser.add_option("-p", "--port", action="store", dest="port", help="django app port")
parser.add_option("-s", "--settings", action="store", dest="settings", help="Django settings module name")
parser.add_option("-f", "--fcgi", action="store_true", dest="fcgi", help="Run fcgi subprocess")
parser.add_option("-n", "--name", action="store", dest="name", help="process name")
(options, _unused_args) = parser.parse_args()
default_port = 8001 if options.fcgi else 8000
host = options.host if options.host else default_host
port = int(options.port) if options.port else default_port
settings = options.settings
process_name = options.name
if options.fcgi:
print >> sys.stderr, "Creating fcgi server on %s:%d" % (host, port)
server = Manager(host, port, settings, process_name=process_name)
print >> sys.stderr, "starting server..."
server.start()
print >> sys.stderr, "server ready."
server.wait()
else:
os.chdir(get_module_directory(settings))
subshell = subprocess.Popen(["python",
"manage.py",
"runserver",
"%s:%d" % (host, port)],
)
subshell.wait()
if __name__ == "__main__":
main()