Django + FastCGI - aumentando in modo casuale OperationalError
Domanda
Sono in esecuzione di un'applicazione Django. Aveva sotto Apache + mod_python prima, ed era tutto OK. Passato alla Lighttpd + FastCGI. Ora ho casualmente ottengo la seguente eccezione (né il luogo né il momento in cui appare sembrano essere prevedibile). Dal momento che è casuale, e appare solo dopo il passaggio a FastCGI, suppongo che abbia qualcosa a che fare con alcune impostazioni.
Trovato un paio di risultati quando googleing, ma sembrano essere correlati a maxrequests impostazione = 1. Comunque, io uso il default, che è 0.
Tutte le idee dove cercare?
PS. Sto utilizzando PostgreSQL. Potrebbe essere legata a quella pure, poiché l'eccezione appare quando si effettua una query di database.
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.
Soluzione 5
Alla fine sono passato ritorna Apache + mod_python (ho avuto altri errori casuali con fcgi, oltre a questo) e tutto è buona e stabile ora.
La questione rimane ancora aperta. Nel caso in cui qualcuno ha questo problema in futuro e lo risolve in grado di registrare la soluzione per riferimenti futuri. :)
Altri suggerimenti
Possibile soluzione: http://groups.google.com/ gruppo / django-users / browse_thread / thread / 2c7421cdb9b99e48
Fino a poco tempo ero curioso di testare questo su Django 1.1.1. sarà questo un'eccezione essere gettato ancora una volta ... sorpresa, eccolo di nuovo. Mi ci sono voluti un po ' il tempo per eseguire il debug di questo, suggerimento utile è stato che mostra solo quando (pre) biforcano. Così, per coloro che ottenere in modo casuale tali eccezioni, posso dire ... risolvere il codice :) Ok .. sul serio, non ci sono sempre alcuni modi di fare questo, in modo da mi permetta di abeti spiegare dove è un problema in primo luogo. Se si accede a dati quando uno dei vostri moduli importerà come, ad esempio lettura configurazione dal banca dati allora otterrete questo errore. Quando l'applicazione FastCGI-prefork inizia, prima importa tutti i moduli, e solo dopo questo forchette bambini. Se avete stabilito la connessione db durante l'importazione di tutti i processi per bambini avrà una copia esatta di quella oggetto. Questo collegamento è essere chiusa al termine della fase di richiesta (Segnale request_finished). Quindi prima figlio che sarà chiamato a processare la richiesta, si chiuderà questo connessione. Ma cosa accadrà a il resto dei processi figlio? Essi si credono di avere aperto e presumibilmente connessione a lavorare db, quindi qualsiasi operazione db causerà un eccezione. Perché questo non sta mostrando in modello di esecuzione filettata? Credo perché thread utilizzano stesso oggetto e sapere quando qualsiasi altro filo è chiusura della connessione. Come risolvere questo problema? Il modo migliore è quello di fissare il codice ... ma questo può essere difficile a volte. Altra opzione, a mio parere del tutto pulito, è quello di scrivere da qualche parte nella tua applicazione piccolo pezzo di codice:
from django.db import connection
from django.core import signals
def close_connection(**kwargs):
connection.close()
signals.request_started.connect(close_connection)
Non pensiero ideale, che collega due volte per il DB è una soluzione al meglio.
Soluzione possibile. Utilizza il pool di connessioni (pgpool, pgbouncer), in modo da avere le connessioni DB pool e stabile, e consegnato veloce per i demoni fcgi
Il problema è che questo fa scattare un altro bug, psycopg2 sollevando un InterfaceError , perché sta cercando di staccare due volte (pgbouncer già gestito questo).
Ora il colpevole è Django segnale request_finished innescando connection.close () , e non riuscendo ad alta voce anche se è stato già scollegata. Non credo che questo comportamento è desiderato, come se la richiesta già finito, non ci preoccupiamo per la connessione DB più. Una patch per correggere questo dovrebbe essere semplice.
Il traceback rilevanti:
/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 gestione delle eccezioni qui potrebbe aggiungere più clemenza:
/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)
O potrebbe essere gestito meglio su psycopg2, in modo da non gettare errori irreversibili, se tutto quello che stiamo cercando di fare è scollegare e che già è:
/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
Oltre a questo, io sono a corto di idee.
Nel interruttore, hai cambiato le versioni client / server PostgreSQL?
Ho visto problemi simili con php + mysql, e il colpevole era un'incompatibilità tra le versioni client / server (anche se avevano la stessa versione principale!)
profuma come un possibile problema di threading. Django è non garantita thread-safe, anche se i documenti in file sembrano indicare che Django / fcgi può essere eseguito in questo modo. Provare a eseguire con prefork e poi battere la merda di server. Se il problema va via ...
Forse la variabile PYTHONPATH e l'ambiente PATH è diverso per entrambe le configurazioni (Apache + mod_python e lighttpd + FastCGI).
Ho risolto un problema simile quando si utilizza un modello di geodjango che non stava usando l'ORM predefinito per una delle sue funzioni. Quando ho aggiunto una linea per chiudere manualmente il collegamento l'errore è andato via.
http://code.djangoproject.com/ticket/9437
Vedo ancora l'errore casuale (~ 50% delle richieste), quando fare cose con login utente / sessioni tuttavia.
Sono andato con lo stesso problema di recente (lighttpd, FastCGI e Postgre). Ricerca di una soluzione per giorni senza successo, e come ultima risorsa passato a mysql. Il problema è scomparso.
Perché non la memorizzazione nella cache di sessione? Impostare
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
Inoltre si può provare uso postgres con pgbouncer . (Postgres - Server prefork e non come molti Collega / scollega per volta), ma in primo luogo controllare il postgresql.log
Un'altra versione -. Si dispone di molti record nelle tabelle di sessione e di pulizia django-admin.py può aiutare
Il problema potrebbe essere principalmente con le importazioni. Atleast questo è quello che mi è successo. Ho scritto la mia soluzione dopo aver trovato nulla dal web. Si prega di controllare il mio blogpost qui: semplice utility Python per controllare tutte le importazioni in il progetto
Naturalmente questo solo vi aiuterà ad arrivare alla soluzione del problema originale abbastanza rapidamente e non la soluzione reale per il vostro problema di per sé.
Cambia da method = prefork a method = filettato ha risolto il problema per me.
cerco di dare una risposta a questo, anche se non si utilizza I'am Django, ma piramide come la struttura. Stavo correndo in questo problema da molto tempo. Il problema era, che è stato davvero difficile produrre questo errore per le prove ... Comunque. Finalmente ho risolto scavando attraverso l'intero roba di sessioni, sessioni con ambito, le istanze di sessioni, i motori e le connessioni, ecc ho trovato questo:
Questo approccio aggiunge semplicemente un ascoltatore al pool di connessioni del motore. In chi ascolta una selezione statica viene interrogato al database. Se fallisce il pool tenta di stabilire una nuova connessione al database, prima di danneggiarsi a tutti. Importante: Questo accade prima di ogni altra roba è gettato al database. Quindi è possibile controllare la validità della connessione di controllo ciò che impedisce il resto del codice di fallire.
Questa non è una soluzione pulita in quanto non risolvono l'errore in sé, ma funziona come un fascino. Spero che questo aiuta qualcuno.
Una citazione del caso:
"2019 anyone?"
- half of YouTube comments, circa 2019
Se qualcuno è ancora alle prese con questo, assicurarsi che la vostra applicazione è "entusiasmo forking" tali risorse che il driver Python DB (psycopg2
per me) non è la condivisione tra i processi.
Ho risolto questo problema in uWSGI aggiungendo l'opzione lazy-apps = true
, che causa è di generare i processi app destra fuori del cancello, piuttosto che aspettare per copia su scrittura. Immagino altri host WSGI / FastCGI hanno opzioni simili.
Avete considerato declassamento a Python 2.5.x (2.5.4 in particolare)? Non credo che Django sarebbe considerato maturo su Python 2.6 dal momento che ci sono alcuni cambiamenti all'indietro incompatibili. Tuttavia, dubito che questo risolverà il problema.
Inoltre, Django 1.0.2 corretti alcuni piccoli bug nefasti in modo da assicurarsi che si sta eseguendo questo. Questo molto ben potrebbe risolvere il problema.