2008-12-26 17 views
8

Ich benutze eine Django-Anwendung. Hatte es unter Apache + mod_python schon, und es war alles in Ordnung. Auf Lighttpd + FastCGI umgeschaltet. Jetzt bekomme ich zufällig die folgende Ausnahme (weder der Ort noch die Zeit, wo es erscheint, scheinen vorhersehbar zu sein). Da es zufällig ist und erst nach dem Wechsel zu FastCGI erscheint, nehme ich an, dass es etwas mit einigen Einstellungen zu tun hat.Django + FastCGI - zufälliges Anheben OperationalError

Gefunden einige Ergebnisse, wenn sie googeln, aber sie scheinen mit der Einstellung maxrequests = 1 verwandt zu sein. Allerdings verwende ich die Standardeinstellung, die 0 ist.

Irgendwelche Ideen, wo suchen?

PS. Ich benutze PostgreSQL. Kann auch damit zusammenhängen, da die Ausnahme beim Erstellen einer Datenbankabfrage erscheint.

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. 

Antwort

0

Am Ende wechselte ich wieder zu Apache + mod_python (ich hatte andere zufällige Fehler mit fcgi, neben diesem einen) und alles ist jetzt gut und stabil.

Die Frage bleibt noch offen. Falls jemand dieses Problem in der Zukunft hat und es löst, kann es die Lösung hier für zukünftige Referenz aufzeichnen. :)

+2

Das löst das Problem nicht selbst. Umgehe es einfach. : P könnte für manche Leute keine Option sein. – pkoch

0

Haben Sie im Switch die PostgreSQL Client/Server-Versionen geändert?

Ich habe ähnliche Probleme mit PHP + MySQL gesehen, und der Täter war eine Inkompatibilität zwischen den Client/Server-Versionen (auch wenn sie die gleiche Hauptversion hatten!)

+0

Nein. Ich habe nur Apache + mod_python auf Lighttpd + FastCGI umgestellt. – ibz

0

Riecht wie ein mögliches threading Problem. Django ist nicht garantiert thread-sicher, obwohl die In-Datei-Dokumente darauf hindeuten, dass Django/FCGI auf diese Weise ausgeführt werden kann. Versuchen Sie, mit Prefork zu laufen und dann den Mist aus dem Server zu schlagen. Wenn das Problem verschwindet ...

+0

Ich benutze bereits Prefork. – ibz

0

Möglicherweise ist die Umgebungsvariable PYTHONPATH und PATH für beide Setups unterschiedlich (Apache + mod_python und lighttpd + FastCGI).

0

Ich behob ein ähnliches Problem bei der Verwendung eines Geodjango-Modells, das nicht das Standard-ORM für eine seiner Funktionen verwendet. Als ich eine Leitung hinzufügte, um die Verbindung manuell zu schließen, ging der Fehler weg.

http://code.djangoproject.com/ticket/9437

ich immer noch den Fehler sehe zufällig (~ 50% der Anfragen), wenn jedoch Sachen mit Benutzer-Login/Sitzungen zu tun.

-1

Haben Sie in Erwägung gezogen, auf Python 2.5.x herunterzuspielen (speziell 2.5.4)? Ich denke nicht, dass Django auf Python 2.6 als ausgereift gelten würde, da es einige rückwärtskompatible Änderungen gibt. Ich bezweifle jedoch, dass dies Ihr Problem beheben wird.

Außerdem hat Django 1.0.2 einige schändliche kleine Fehler behoben, also stellen Sie sicher, dass Sie das ausführen. Das könnte Ihr Problem beheben.

0

Ich ging vor kurzem das gleiche Problem (Lighttpd, Fastcgi & Postgre). Gesucht nach einer Lösung für Tage ohne Erfolg, und als letztes Mittel zu MySQL gewechselt. Das Problem ist weg.

0

Warum wird die Sitzung nicht im Cache gespeichert? Set

SESSION_ENGINE = "django.contrib.sessions.backends.cache" 

Sie können auch Verwendung Postgres mit pgbouncer versuchen (Postgres - prefork-Server und nicht wie viele/Deaktiviert die pro Zeit), aber zunächst prüfen Sie Ihre postgresql.log.

Eine andere Version - Sie haben viele Datensätze in Sitzungstabellen und django-admin.py Cleanup kann helfen.

0

Das Problem könnte hauptsächlich mit Importen sein. Zumindest ist das mit mir passiert. Ich habe meine eigene Lösung geschrieben, nachdem ich nichts aus dem Internet gefunden habe. Bitte überprüfen Sie meinen Blogpost hier: Simple Python Utility to check all Imports in your project

Natürlich wird dies Ihnen nur helfen, um die Lösung des ursprünglichen Problems ziemlich schnell und nicht die eigentliche Lösung für Ihr Problem an sich zu bekommen.

0

Wechsel von method = Prefork zu method = Gewinde löste das Problem für mich.

3

Mögliche Lösung: http://groups.google.com/group/django-users/browse_thread/thread/2c7421cdb9b99e48

Bis vor kurzem war ich neugierig 1.1.1 diese auf Django zu testen. Wird diese Ausnahme wieder geworfen ... Überraschung, da war es wieder. Es dauerte einige Zeit, um dies zu debuggen, hilfreicher Hinweis war , dass es nur zeigt, wenn (pre) Gabelung. erste für diejenigen also, die diese Ausnahmen zufällig bekommen, kann ich sagen ... fix Code :) Ok .. ernst, da sind dies immer einige Möglichkeiten zu tun, so lassen Sie mich erklären, wo Tannen ist ein Problem . Wenn Sie auf die Datenbank zugreifen, wenn eines Ihrer Module als z. Lesen der Konfiguration von Datenbank dann erhalten Sie diesen Fehler. Wenn Ihr fastcgi-prefork Anwendung beginnt, zuerst importiert sie alle Module, und erst nach dieser Gabeln Kinder. Wenn Sie DB-Verbindung beim Import eingerichtet haben alle Kinder verarbeitet eine exakte Kopie dieses Objekt haben wird. Diese Verbindung wird am Ende der Anforderungsphase geschlossen (request_finished signal). So zuerst Kind, das aufgerufen wird, Ihre Anfrage zu verarbeiten, wird diese Verbindung schließen. Aber was passiert mit der Rest der Kind-Prozesse? Sie wird glauben, dass sie offen und vermutlich Arbeits Verbindung zum db, so dass jeder db Betrieb verursacht eine Ausnahme. Warum wird dies nicht in Thread-Ausführungsmodell angezeigt? Ich nehme an, weil Threads das gleiche Objekt verwenden und wissen, wenn ein anderer Thread schließende Verbindung ist. Wie behebe ich das? Der beste Weg ist, Ihren Code zu reparieren ... aber das kann manchmal schwierig sein. Andere Option, meiner Meinung nach recht sauber, ist irgendwo in Ihrem Anwendung kleines Stück Code zu schreiben:

from django.db import connection 
from django.core import signals 
def close_connection(**kwargs): 
    connection.close() 
signals.request_started.connect(close_connection) 

Nicht ideal Gedanke, zweimal an die DB verbindet eine Abhilfe besten ist.


Mögliche Lösung: mit Verbindungspooling (pgpool, pgbouncer), so dass Sie haben DB-Verbindungen vereinigt und stabil und gab schnell auf Ihre FCGI Daemons.

Das Problem ist, dass dies ein weiterer Fehler auslöst, psycopg2 Auslösen eines InterfaceError, weil es versucht, zweimal zu trennen (pgbouncer dies bereits behandelt).

Jetzt ist der Schuldige Signal Django Auslösung connection.close request_finished(), und andernfalls, wenn es laut sogar bereits getrennt wurde. Ich glaube nicht, dass dieses Verhalten erwünscht ist, als ob die Anfrage bereits beendet wäre, uns ist die DB-Verbindung nicht mehr wichtig. Ein Patch zur Korrektur sollte einfach sein.

Die entsprechenden Zurückverfolgungs:

/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> 

Ausnahme hier Umgang mit mehr Nachsicht könnte hinzufügen:

/usr/local/lib/python2.6/dist-packages/Django-1.1.1-py2 .6.egg/django/db/__ init__.py

63 # when a Django request is finished. 
    64 def close_connection(**kwargs): 
    65  connection.close() 
    66 signals.request_finished.connect(close_connection) 

Oder es könnte besser auf psycopg2 behandelt werden, so nicht fatale Fehler auslösen, wenn alles, was wir disconn zu tun versuchen ist ect und es ohnehin schon ist:

/usr/local/lib/python2.6/dist-packages/Django-1.1.1-py2.6.egg/django/db/backends/__init__.py

74  def close(self): 
    75   if self.connection is not None: 
    76    self.connection.close() 
    77    self.connection = None 

Ansonsten bin ich kurz auf Ideen.

0

Ich versuche eine Antwort darauf zu geben, auch wenn ich nicht Django sondern Pyramide als Rahmen benutze. Ich bin seit langem auf dieses Problem gestoßen. Problem war, dass es wirklich schwierig war, diesen Fehler für Tests zu erzeugen ... Jedenfalls. Ich kann es schließlich gelöst, indem durch das ganze Zeug von Sitzungen zu graben, scoped Sitzungen, Fällen von Sitzungen, Motoren und Verbindungen usw. fand ich dies:

http://docs.sqlalchemy.org/en/rel_0_7/core/pooling.html#disconnect-handling-pessimistic

Dieser Ansatz fügt einfach einen Zuhörer an den Verbindungspool der Motor. Im Listener wird eine statische Auswahl an die Datenbank abgefragt. Wenn der Pool fehlschlägt, versuchen Sie, eine neue Verbindung zur Datenbank herzustellen, bevor überhaupt ein Fehler auftritt. Wichtig: Dies geschieht, bevor irgendwelche anderen Sachen in die Datenbank geworfen werden. So ist es möglich, die Verbindung vorab zu überprüfen, was verhindert, dass der Rest Ihres Codes fehlschlägt.

Dies ist keine saubere Lösung, da es den Fehler selbst nicht löst, aber es funktioniert wie ein Charme. Hoffe, das hilft jemandem.

Verwandte Themen