So you whipped up an awesome
Django (
src) project following the instructions on the
documentation site, and now you want to deploy it on a production slice. Inspired by RoR mongrels deployments, you setup an
nginx (
src) load-balancer that will
proxy_pass requests to a cluster of Django instances, each inside an ultra-fast
CherryPy (
src) http server wrapper. Perhaps you chose to use
django_cpserver (
src) to extend the standard
manage.py with a slick runcpserver command to fire up your django web app instances. Maybe you even write a quick utility script to fire up your django cluster all in one go:
#!/usr/bin/env python
#
# Utility script for firing up the django cluster.
#
# To use this library on python 2.5:
# http://code.google.com/p/python-multiprocessing/
#
# $Id: cluster.py,v 1.2 2009/11/17 19:44:25 l8rs Exp $
import multiprocessing
import subprocess
#from config.cluster import DJANGO_WORKERS
DJANGO_WORKERS = [
'./manage.py runcpserver host=127.0.0.1 port=8000 daemonize',
'./manage.py runcpserver host=127.0.0.1 port=8001 daemonize',
'./manage.py runcpserver host=127.0.0.1 port=8002 daemonize',
'./manage.py runcpserver host=127.0.0.1 port=8003 daemonize',
]
def work(cmd):
return subprocess.call(cmd, shell=True)
def start():
count = len(DJANGO_WORKERS)
pool = multiprocessing.Pool(count)
print pool.map(work, DJANGO_WORKERS)
if __name__ == '__main__':
start()
Ok, but when you finally start hitting the server with requests, to your shock and horror, the app that ran fine when started with `manage.py runserver` or even `manage.py runcpserver` without daemonize now can't find any of the local modules in your application?!
Traceback (most recent call last):
File "/usr/local/lib/python2.6/dist-packages/cherrypy/wsgiserver/__init__.py", line 1210, in communicate
req.respond()
File "/usr/local/lib/python2.6/dist-packages/cherrypy/wsgiserver/__init__.py", line 729, in respond
self.server.gateway(self).respond()
File "/usr/local/lib/python2.6/dist-packages/cherrypy/wsgiserver/__init__.py", line 1889, in respond
response = self.req.server.wsgi_app(self.env, self.start_response)
File "/usr/local/lib/python2.6/dist-packages/django/core/handlers/wsgi.py", line 241, in __call__
response = self.get_response(request)
File "/usr/local/lib/python2.6/dist-packages/django/core/handlers/base.py", line 76, in get_response
response = middleware_method(request)
File "/usr/local/lib/python2.6/dist-packages/django/middleware/common.py", line 56, in process_request
if (not _is_valid_path(request.path_info) and
File "/usr/local/lib/python2.6/dist-packages/django/middleware/common.py", line 142, in _is_valid_path
urlresolvers.resolve(path)
File "/usr/local/lib/python2.6/dist-packages/django/core/urlresolvers.py", line 309, in resolve
return get_resolver(urlconf).resolve(path)
File "/usr/local/lib/python2.6/dist-packages/django/core/urlresolvers.py", line 220, in resolve
for pattern in self.url_patterns:
File "/usr/local/lib/python2.6/dist-packages/django/core/urlresolvers.py", line 249, in _get_url_patterns
patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
File "/usr/local/lib/python2.6/dist-packages/django/core/urlresolvers.py", line 244, in _get_urlconf_module
self._urlconf_module = import_module(self.urlconf_name)
File "/usr/local/lib/python2.6/dist-packages/django/utils/importlib.py", line 35, in import_module
__import__(name)
File "/home/user/src/django/myproj/../myproj/urls.py", line 7, in
from myapp.module import views
ImportError: No module named myapp.module
Well, silly goose, the answer is simple (and nowhere to be found on all the internet)! You need to make sure the daemon user has permission to access the source of your web app! The default user for this setup is www-data. And when you're testing out the app, you may have put it in ~/src or something owned by your dev user. Also, when you run with daemonize on, you may have been tempted to prepend a sudo to allow the runcpserver code to generate it's default /var/run/cpserver_port.pid file... The simple fix is to pass server_user= and server_group= to the `manage.py runcpserver` command (though passing in root to these is clearly not advised from a security stand-point). The proper fix is to put your django code in a place it will live in production (/var/www/...), and to stamp it with all the right user and group permissions.
Hopefully this post saves you some heart-ache!