2011-10-27 11 views
41

Ho django 1.3 sul server remoto dietro Nginx.Django Tubo rotto in modalità di debug

Se eseguo django con apache + mod_wsgi, posso controllare gli errori nei file di registro di apache. Va bene, ma mi piacerebbe avere in console.

Se eseguo il proprio server di sviluppo django, ottengo errori con stacktrace in console solo quando DEBUG = False. Uscite della console in modalità DEBUG

Exception happened during processing of request from (..., ...) 
Traceback (most recent call last): 
    File "/usr/local/python/lib/python2.7/SocketServer.py", line 284, in _handle_request_noblock 
    self.process_request(request, client_address) 
    File "/usr/local/python/lib/python2.7/SocketServer.py", line 310, in process_request 
    self.finish_request(request, client_address) 
    File "/usr/local/python/lib/python2.7/SocketServer.py", line 323, in finish_request 
    self.RequestHandlerClass(request, client_address, self) 
    File "/usr/local/python/lib/python2.7/site-packages/django/core/servers/basehttp.py", line 570, in __init__ 
    BaseHTTPRequestHandler.__init__(self, *args, **kwargs) 
    File "/usr/local/python/lib/python2.7/SocketServer.py", line 641, in __init__ 
    self.finish() 
    File "/usr/local/python/lib/python2.7/SocketServer.py", line 694, in finish 
    self.wfile.flush() 
    File "/usr/local/python/lib/python2.7/socket.py", line 301, in flush 
    self._sock.sendall(view[write_offset:write_offset+buffer_size]) 
error: [Errno 32] Broken pipe 

Voglio capire perché? Perché django emette solo un'eccezione senza nome? Perché dipende dalla variabile DEBUG.

Questi errori si verificano principalmente viste esterne quando non ho accesso all'oggetto richiesta. Quindi non riesco a prenderlo nel middleware o utilizzando il gestore di registrazione.

AGGIORNAMENTO. Ho notato che se ho richiesto direttamente al server django non ho mai ricevuto Broken pipe. Quindi il problema potrebbe verificarsi mentre il proxy Nginx django?

+0

non ho avuto questo problema su un server live, tuttavia si verifica di tanto in tanto sul server dev django sul mio computer locale. Non sono stato in grado di risolvere questo problema –

+0

Potrebbe essere solo il timeout NGINX prima che django invii la risposta. Qual è il "proxy_read_timeout" impostato nel tuo file nginx.conf? – Nils

risposta

8

Nginx direttiva proxy_intercept_errors off; (disabilitato per impostazione predefinita) è quello che mi serviva

+0

Ciao San4ez, come dici tu sembra disabilitato di default. In che modo la disabilitazione esplicita ha risolto il problema? (Potrei avere un problema correlato ...) – Alex

+0

Non capisco la tua domanda. Immaginare, richiesta proxy di nginx a django upstream e ottiene uno stato di errore (400 o superiore). Se 'proxy_intercept_errors' è disabilitato, la pagina di errore delle risposte di nginx proviene da django. Altrimenti nginx interrompe la lettura della risposta django e invia alla pagina di errore personalizzata dell'utente. Il server Django (o qualsiasi altro) genera errore che il client non legge socket - pipe interrotte – San4ez

+0

Capito; e in realtà questo ha funzionato per me. È strano perché se proxy_intercept_errors è disattivato per impostazione predefinita, disattivarlo esplicitamente non dovrebbe avere alcun effetto. Vedi http://wiki.nginx.org/HttpProxyModule#proxy_intercept_errors – Alex

49

Questo non è davvero un problema con il tuo sito, più con il devserver Django: vedi questo Django ticket. Per dirlo senza mezzi termini, basta ignorarlo poiché si tratta di un errore noto e non verrà risolto.

Nei commenti di quel biglietto una spiegazione abbastanza chiara è data:

Secondo molte fonti il ​​'tubo rotto' è una stranezza normale browser. Ad esempio, il browser legge dal socket e quindi decide che l'immagine che sta leggendo apparentemente non è cambiata. Il browser ora questo (forzatamente) chiude la connessione perché non ha bisogno di più dati. L'altra estremità di questo socket (il python runserver) ora solleva un'eccezione del socket che dice al programma che il client "ha rotto la pipa del socket".

+2

Grazie. Ho visto quel vecchio biglietto prima. Ho appena aggiornato la domanda. – San4ez

2

sono stato in grado di sbarazzarsi di questo

proxy_buffering off;

Arresta il buffer di risposta del server proxy. Ciò porta ad altri problemi dell'applicazione di back-end bloccata a lungo se il client è in una connessione estremamente lenta.

Per renderlo condizionale per richieste particolari, utilizzare X-Accel-Buffering = no nell'intestazione della risposta.

0

Mi sono imbattuto anche in questo problema durante l'utilizzo di tilelite. In realtà è causato da un bug noto e ora corretto in python. È possibile risolvere questo problema applicando la seguente patch:

http://bugs.python.org/issue14574

In caso contrario, è possibile scaricare uno dei più recenti build di pitone.

2

Mi è venuta una patch di scimmia veloce e sporca (non so se sopprime eventuali errori utili), che elimina questo fastidioso errore quando si utilizza "./manage.py runserver" o si eseguono test di LiveServerTestCase.

Basta inserire in qualsiasi punto nel codice, in cui è necessario che:

# Monkeypatch python not to print "Broken Pipe" errors to stdout. 
import SocketServer 
from wsgiref import handlers 
SocketServer.BaseServer.handle_error = lambda *args, **kwargs: None 
handlers.BaseHandler.log_exception = lambda *args, **kwargs: None 
0

ho riparato. Se si utilizzano i collegamenti, il tag di ancoraggio, all'interno della pagina, si deve affrontare il problema "Borken Pipe". Basta usare all'interno del tag link href = '#'. Non lasciare vuoto l'attributo href. Eviterà quel tipo di errore.

4

Ecco un modo per impedire che venga stampato il messaggio su stderr. Solo monkey patch la funzione BaseServer.handle_error. Questo è come lo faccio:

def patch_broken_pipe_error(): 
    """Monkey Patch BaseServer.handle_error to not write 
    a stacktrace to stderr on broken pipe. 
    https://stackoverflow.com/a/7913160""" 
    import sys 
    from SocketServer import BaseServer 

    handle_error = BaseServer.handle_error 

    def my_handle_error(self, request, client_address): 
     type, err, tb = sys.exc_info() 
     # there might be better ways to detect the specific erro 
     if repr(err) == "error(32, 'Broken pipe')": 
      # you may ignore it... 
      logging.getLogger('mylog').warn(err) 
     else: 
      handle_error(self, request, client_address) 

    BaseServer.handle_error = my_handle_error 


patch_broken_pipe_error() 
6

La direttiva nginx (risposta selezionata) non ha funzionato per me, ma unendo le patch di scimmia da Igor Katson e Michael_Scharf fatto:

def patch_broken_pipe_error(): 
    """Monkey Patch BaseServer.handle_error to not write 
    a stacktrace to stderr on broken pipe. 
    http://stackoverflow.com/a/22618740/362702""" 
    import sys 
    from SocketServer import BaseServer 
    from wsgiref import handlers 

    handle_error = BaseServer.handle_error 
    log_exception = handlers.BaseHandler.log_exception 

    def is_broken_pipe_error(): 
     type, err, tb = sys.exc_info() 
     return repr(err) == "error(32, 'Broken pipe')" 

    def my_handle_error(self, request, client_address): 
     if not is_broken_pipe_error(): 
      handle_error(self, request, client_address) 

    def my_log_exception(self, exc_info): 
     if not is_broken_pipe_error(): 
      log_exception(self, exc_info) 

    BaseServer.handle_error = my_handle_error 
    handlers.BaseHandler.log_exception = my_log_exception 

patch_broken_pipe_error() 
+0

Puoi anche abilitare l'opzione proxy_ignore_client_abort nel tuo nginx conf. In questo caso, nginx non interromperà la connessione con il backend se il client (browser) lo fa. – San4ez

+0

Questo codice deve essere inserito in settings.py - usando Django 1.5. –