Django + FastCGI - élever au hasard OperationalError
Question
Je suis en cours d'exécution d'une application Django. Si elle avait sous Apache + mod_python avant, et il était OK. Switched Lighttpd + FastCGI. Maintenant, je reçois au hasard l'exception suivante (ni le lieu ni le moment où il semble semble être prévisible). Comme il est aléatoire, et il semble qu'après le passage à FastCGI, je suppose qu'il a quelque chose à voir avec certains paramètres.
trouvé quelques résultats quand googleing, mais ils semblent être liés à la mise en maxrequests = 1. Cependant, j'utilise la valeur par défaut, qui est 0.
Toutes les idées où chercher?
PS. J'utilise PostgreSQL. Pourrait être liée à cela aussi, puisque l'exception apparaît lors d'une requête de base de données.
File "/usr/lib/python2.6/site-packages/django/core/handlers/base.py", line 86, in get_response
response = callback(request, *callback_args, **callback_kwargs)
File "/usr/lib/python2.6/site-packages/django/contrib/admin/sites.py", line 140, in root
if not self.has_permission(request):
File "/usr/lib/python2.6/site-packages/django/contrib/admin/sites.py", line 99, in has_permission
return request.user.is_authenticated() and request.user.is_staff
File "/usr/lib/python2.6/site-packages/django/contrib/auth/middleware.py", line 5, in __get__
request._cached_user = get_user(request)
File "/usr/lib/python2.6/site-packages/django/contrib/auth/__init__.py", line 83, in get_user
user_id = request.session[SESSION_KEY]
File "/usr/lib/python2.6/site-packages/django/contrib/sessions/backends/base.py", line 46, in __getitem__
return self._session[key]
File "/usr/lib/python2.6/site-packages/django/contrib/sessions/backends/base.py", line 172, in _get_session
self._session_cache = self.load()
File "/usr/lib/python2.6/site-packages/django/contrib/sessions/backends/db.py", line 16, in load
expire_date__gt=datetime.datetime.now()
File "/usr/lib/python2.6/site-packages/django/db/models/manager.py", line 93, in get
return self.get_query_set().get(*args, **kwargs)
File "/usr/lib/python2.6/site-packages/django/db/models/query.py", line 304, in get
num = len(clone)
File "/usr/lib/python2.6/site-packages/django/db/models/query.py", line 160, in __len__
self._result_cache = list(self.iterator())
File "/usr/lib/python2.6/site-packages/django/db/models/query.py", line 275, in iterator
for row in self.query.results_iter():
File "/usr/lib/python2.6/site-packages/django/db/models/sql/query.py", line 206, in results_iter
for rows in self.execute_sql(MULTI):
File "/usr/lib/python2.6/site-packages/django/db/models/sql/query.py", line 1734, in execute_sql
cursor.execute(sql, params)
OperationalError: server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
La solution 5
En fin de compte je suis revenu à Apache + mod_python (j'avais d'autres erreurs aléatoires avec fcgi, en plus de celui-ci) et tout est bon et stable maintenant.
La question reste ouverte. Dans le cas où quelqu'un a ce problème à l'avenir et résout ils peuvent enregistrer ici la solution pour référence future. :)
Autres conseils
Solution possible: http://groups.google.com/ groupe / django-users / browse_thread / fil / 2c7421cdb9b99e48
Jusqu'à récemment, je suis curieux de tester ceci sur Django 1.1.1. Cela va-t-il exception être jeté à nouveau ... surprise, là, il était à nouveau. Il m'a fallu un certain le temps de débugger, conseil utile était qu'il montre que lorsque (pré) bifurquer. Donc, pour ceux qui se au hasard ces exceptions, je peux dire ... corriger votre code :) Ok .. sérieusement, il sont toujours quelques façons de le faire, donc permettez-moi de sapins expliquer où est Le premier problème. Si vous accédez à la base de données lorsque l'un de vos modules importera comme, par exemple lecture de la configuration de base de données, vous obtiendrez cette erreur. Lorsque votre application FastCGI-prefork commence, d'abord, il importe tous les modules, et seulement après ces enfants fourches. Si vous avez établi une connexion db lors de l'importation de tous les processus enfants aura une copie exacte de cette objet. Cette connexion est fermé à la fin de la phase de demande (Signal de request_finished). Alors d'abord enfant qui sera appelé à traiter votre demande, fermera ses portes ce lien. Mais ce qui arrivera à le reste des processus enfants? Ils croira qu'ils ont ouvert et connexion sans doute au travail db, de sorte que toute opération db provoquera une exception. Pourquoi ce ne montre pas dans modèle d'exécution filetée? Je suppose parce que les sujets utilisent un même objet et savoir quand tout autre fil est fermeture de la connexion. Comment régler ceci? La meilleure façon est de fixer votre code ... mais cela peut être parfois difficile. Une autre option, tout à fait à mon avis propre, est d'écrire quelque part dans votre l'application petit morceau de code:
from django.db import connection
from django.core import signals
def close_connection(**kwargs):
connection.close()
signals.request_started.connect(close_connection)
Non pensée idéale, reliant deux fois à la base de données est une solution de contournement au mieux.
Solution possible:. Utilisant la mise en commun connexion (pgpool, de pgbouncer), de sorte que vous avez des connexions DB mis en commun et stable, et remis rapidement à vos daemons FCGI
Le problème est que cela déclenche un autre bug, psycopg2 soulevant un InterfaceError parce qu'il essaie de déconnecter deux fois (pgbouncer déjà traité ce sujet).
Maintenant, le coupable est un signal Django request_finished déclenchement connection.close () , et à défaut fort, même si elle était déjà déconnecté. Je ne pense pas que ce comportement est souhaité, comme si la demande déjà terminée, nous ne nous soucions pas de la connexion DB plus. Un patch pour corriger cela devrait être simple.
Le retraçage pertinent:
/usr/local/lib/python2.6/dist-packages/Django-1.1.1-py2.6.egg/django/core/handlers/wsgi.py in __call__(self=<django.core.handlers.wsgi.WSGIHandler object at 0x24fb210>, environ={'AUTH_TYPE': 'Basic', 'DOCUMENT_ROOT': '/storage/test', 'GATEWAY_INTERFACE': 'CGI/1.1', 'HTTPS': 'off', 'HTTP_ACCEPT': 'application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5', 'HTTP_ACCEPT_ENCODING': 'gzip, deflate', 'HTTP_AUTHORIZATION': 'Basic dGVzdGU6c3VjZXNzbw==', 'HTTP_CONNECTION': 'keep-alive', 'HTTP_COOKIE': '__utma=175602209.1371964931.1269354495.126938948...none); sessionid=a1990f0d8d32c78a285489586c510e8c', 'HTTP_HOST': 'www.rede-colibri.com', ...}, start_response=<function start_response at 0x24f87d0>)
246 response = self.apply_response_fixes(request, response)
247 finally:
248 signals.request_finished.send(sender=self.__class__)
249
250 try:
global signals = <module 'django.core.signals' from '/usr/local/l.../Django-1.1.1-py2.6.egg/django/core/signals.pyc'>, signals.request_finished = <django.dispatch.dispatcher.Signal object at 0x1975710>, signals.request_finished.send = <bound method Signal.send of <django.dispatch.dispatcher.Signal object at 0x1975710>>, sender undefined, self = <django.core.handlers.wsgi.WSGIHandler object at 0x24fb210>, self.__class__ = <class 'django.core.handlers.wsgi.WSGIHandler'>
/usr/local/lib/python2.6/dist-packages/Django-1.1.1-py2.6.egg/django/dispatch/dispatcher.py in send(self=<django.dispatch.dispatcher.Signal object at 0x1975710>, sender=<class 'django.core.handlers.wsgi.WSGIHandler'>, **named={})
164
165 for receiver in self._live_receivers(_make_id(sender)):
166 response = receiver(signal=self, sender=sender, **named)
167 responses.append((receiver, response))
168 return responses
response undefined, receiver = <function close_connection at 0x197b050>, signal undefined, self = <django.dispatch.dispatcher.Signal object at 0x1975710>, sender = <class 'django.core.handlers.wsgi.WSGIHandler'>, named = {}
/usr/local/lib/python2.6/dist-packages/Django-1.1.1-py2.6.egg/django/db/__init__.py in close_connection(**kwargs={'sender': <class 'django.core.handlers.wsgi.WSGIHandler'>, 'signal': <django.dispatch.dispatcher.Signal object at 0x1975710>})
63 # when a Django request is finished.
64 def close_connection(**kwargs):
65 connection.close()
66 signals.request_finished.connect(close_connection)
67
global connection = <django.db.backends.postgresql_psycopg2.base.DatabaseWrapper object at 0x17b14c8>, connection.close = <bound method DatabaseWrapper.close of <django.d...ycopg2.base.DatabaseWrapper object at 0x17b14c8>>
/usr/local/lib/python2.6/dist-packages/Django-1.1.1-py2.6.egg/django/db/backends/__init__.py in close(self=<django.db.backends.postgresql_psycopg2.base.DatabaseWrapper object at 0x17b14c8>)
74 def close(self):
75 if self.connection is not None:
76 self.connection.close()
77 self.connection = None
78
self = <django.db.backends.postgresql_psycopg2.base.DatabaseWrapper object at 0x17b14c8>, self.connection = <connection object at 0x1f80870; dsn: 'dbname=co...st=127.0.0.1 port=6432 user=postgres', closed: 2>, self.connection.close = <built-in method close of psycopg2._psycopg.connection object at 0x1f80870>
La gestion des exceptions ici pourrait ajouter plus de clémence:
/usr/local/lib/python2.6/dist-packages/Django-1.1.1-py2.6.egg/django/db / __ __ initialisation. Py
63 # when a Django request is finished.
64 def close_connection(**kwargs):
65 connection.close()
66 signals.request_finished.connect(close_connection)
Ou il pourrait être traité mieux sur psycopg2, afin de ne pas jeter des erreurs fatales si tout ce que nous essayons de faire est de déconnecter et il est déjà:
/usr/local/lib/python2.6/dist-packages/Django-1.1.1-py2.6.egg/django/db/backends / __ __ initialisation. Py
74 def close(self):
75 if self.connection is not None:
76 self.connection.close()
77 self.connection = None
Autre que cela, je suis à court d'idées.
Dans le commutateur, avez-vous changé PostgreSQL versions client / serveur?
J'ai vu des problèmes similaires avec php + mysql, et le coupable était une incompatibilité entre les versions client / serveur (même si elles ont la même version majeure!)
Smells comme un problème de filetage possible. Django est pas thread-safe garantie bien que les documents en fichier semblent indiquer que Django / FCGI peut fonctionner de cette façon. Essayez d'exécuter avec prefork puis battre la merde hors du serveur. Si le problème disparaît ...
Peut-être la variable PYTHONPATH et environnement PATH est différent pour les deux configurations (Apache + mod_python et lighttpd + FastCGI).
Correction d'un problème similaire lors de l'utilisation d'un modèle de GeoDjango qui n'a pas été en utilisant l'ORM par défaut pour l'une de ses fonctions. Quand j'ai ajouté une ligne pour fermer manuellement la connexion l'erreur a disparu.
http://code.djangoproject.com/ticket/9437
Je vois toujours l'erreur au hasard (~ 50% des demandes) lorsque vous faites des choses avec connexion utilisateur / sessions cependant.
Je suis passé par le même problème récemment (lighttpd, FastCGI et postgre). Recherché une solution pour les jours sans succès, et en dernier recours commuté à MySQL. Le problème a disparu.
Pourquoi ne pas stocker session en cache? Set
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
Vous pouvez également essayer postgres d'utilisation avec pgbouncer . (Postgres - serveur prefork et n'aiment pas beaucoup / déconnexions par Relie temps), mais tout d'abord vérifier votre postgresql.log
Une autre version -. Vous avez plusieurs enregistrements dans les tables de session et nettoyage django-admin.py peut aider
Le problème pourrait être principalement avec les importations. Atleast thats ce qui est arrivé à moi. J'ai écrit ma propre solution après avoir trouvé rien à partir du Web. S'il vous plaît vérifier mon blogpost ici: Utilitaire simple Python pour vérifier toutes les importations en votre projet
Ofcourse cela ne fera que vous aider à arriver à la solution de la question initiale assez rapidement et non la solution réelle pour votre problème en lui-même.
= méthode de changement prefork à la méthode = filetée a résolu le problème pour moi.
J'essaie de donner une réponse à cette même si I'am ne pas utiliser django mais pyramide comme cadre. Je courais dans ce problème depuis longtemps. Le problème était qu'il était vraiment difficile de produire cette erreur pour les tests ... Quoi qu'il en soit. Enfin je l'ai résolu en creusant à travers l'ensemble des choses, séances scope, les instances des sessions, des moteurs et des connexions, etc. Je trouve ceci:
http://docs.sqlalchemy.org/ fr / rel_0_7 / core / pooling.html # déconnexion de manutention-pessimiste
Cette approche ajoute simplement un auditeur à la piscine de connexion du moteur. Dans l'auditeur une sélection statique est la base de données interrogé. Si elle échoue la piscine essayez d'établir une nouvelle connexion à la base de données avant qu'il ne tombe en panne à tout. Important: Cela se produit avant toute autre substance est jeté à la base de données. Il est donc possible d'effectuer une pré connexion à cocher ce qui empêche le reste de votre code de défaut.
Ce n'est pas une solution propre car il ne résout pas l'erreur elle-même, mais cela fonctionne comme un charme. Espérons que cela aide quelqu'un.
Une citation applicable:
"2019 anyone?"
- half of YouTube comments, circa 2019
Si quelqu'un est toujours aux prises avec cela, assurez-vous que votre application est « avec impatience bifurquer » de telle sorte que votre pilote DB Python (de psycopg2
pour moi) ne partage des ressources entre les processus.
Je résolu cette question uwsgi en ajoutant l'option lazy-apps = true
, ce qui provoque est à fork d'application dès la sortie de la porte, plutôt que d'attendre la copie en écriture. J'imagine que d'autres hôtes WSGI / FastCGI ont des options similaires.
Avez-vous envisagé à Python 2.5.x dévalorisation (2.5.4 spécifiquement)? Je ne pense pas que Django serait considéré comme matures sur Python 2.6 car il y a des changements en arrière incompatibles. Cependant, je doute que cela va résoudre votre problème.
En outre, Django 1.0.2 a corrigé quelques petits bugs infâmes font donc que vous exécutez cela. Ce pourrait très bien résoudre votre problème.