Вы можете быть укушены следующей ошибкой django [1] (которая еще не исправлена в ветке 1.4)
обходной путь: вручную примените fix к источникам django или используйтепотокобезопасная оболочка вокруг модуля wsgi, как показано ниже (мы используем это в производственных системах)
from __future__ import with_statement
from django.core.handlers.wsgi import WSGIHandler as DjangoWSGIHandler
from threading import Lock
__copyright__ = "Jibe"
class WSGIHandler(DjangoWSGIHandler):
"""
This provides a threadsafe drop-in replacement of django's WSGIHandler.
Initialisation of django via a multithreaded wsgi handler is not safe.
It is vulnerable to a A-B B-A deadlock.
When two threads bootstrap django via different urls you have a change to hit
the following deadlock.
thread 1 thread 2
view A view B
import file foo import lock foo import file bar import lock bar
bootstrap django lock AppCache.write_lock
import file bar import lock bar <-- blocks
bootstrap django lock AppCache.write_lock <----- deadlock
workaround for an AB BA deadlock: wrap it in a lock C.
lock C lock C
lock A lock B
lock B lock A
release B release A
release A release A
release C release C
Thats exactly what this class does, but... only for the first few calls.
After that we remove the lock C. as the AppCache.write_lock is only held when django is booted.
If we would not remove the lock C after the first few calls, that would make the whole app single threaded again.
Usage:
in your wsgi file replace the following lines
import django.core.handlers.wsgi.WSGIHandler
application = django.core.handlers.wsgi.WSGIHandler
by
import threadsafe_wsgi
application = threadsafe_wsgi.WSGIHandler
FAQ:
Q: why would you want threading in the first place ?
A: to reduce memory. Big apps can consume hundeds of megabytes each. adding processes is then much more expensive than threads.
that memory is better spend caching, when threads are almost free.
Q: this deadlock, it looks far-fetched, is this real ?
A: yes we had this problem on production machines.
"""
__initLock = Lock() # lock C
__initialized = 0
def __call__(self, environ, start_response):
# the first calls (4) we squeeze everybody through lock C
# this basically serializes all threads
MIN_INIT_CALLS = 4
if self.__initialized < MIN_INIT_CALLS:
with self.__initLock:
ret = DjangoWSGIHandler.__call__(self, environ, start_response)
self.__initialized += 1
return ret
else:
# we are safely bootrapped, skip lock C
# now we are running multi-threaded again
return DjangoWSGIHandler.__call__(self, environ, start_response)
и в вашем wsgi.py
используйте следующий код
from threadsafe_wsgi.handlers import WSGIHandler
django_handler = WSGIHandler()
[1]https://code.djangoproject.com/ticket/18251