web-dev-qa-db-fra.com

Django Broken pipe en mode Debug

J'ai Django 1.3 sur le serveur distant derrière Nginx. 

Si je lance Django avec Apache + mod_wsgi, je peux détecter les erreurs dans les fichiers journaux Apache. C'est bon mais j'aimerais avoir en console.

Si j'exécute le propre serveur de développement de Django, les erreurs avec stacktrace dans la console ne sont générées que lorsque DEBUG = False. En mode DEBUG, sorties de la console

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

Je veux comprendre pourquoi? Pourquoi Django produit-il simplement une exception sans nom? Pourquoi cela dépend-il de la variable DEBUG?.

Cette erreur se produit principalement en dehors des vues lorsque je n'ai pas accès à l'objet de requête. Donc, je ne peux pas l'attraper dans le middleware ou en utilisant le gestionnaire de journalisation.

METTRE À JOUR. J'ai remarqué que si je demande directement au serveur Django, je ne reçois jamais de tuyau cassé. Donc, le problème peut-il se produire lorsque Nginx proxy django? 

47
San4ez

La directive Nginx proxy_intercept_errors off; (désactivée par défaut) est ce dont j'avais besoin

8
San4ez

Ce n'est pas vraiment un problème avec votre site, mais plutôt avec le devserver de Django: voir ce billet Django . Pour le dire franchement, ignorez-le, car il s'agit d'une erreur connue et ne sera pas corrigé.

Dans les commentaires de ce ticket, une explication assez claire est donnée:

Selon de nombreuses sources, le "tuyau cassé" est une bizarrerie normale pour les navigateurs. Par exemple, le navigateur lit à partir du socket, puis décide que l'image qu'il a lue n'a apparemment pas changé. Le navigateur maintenant cela (force) ferme la connexion car il n'a pas besoin de plus de données. L'autre extrémité de ce socket (le serveur d'exécution python) déclenche maintenant une exception de socket indiquant au programme que le client 'a cassé le tube de socket'.

54
jro

La directive nginx (réponse cochée) n'a pas fonctionné pour moi, mais la combinaison des patchs de singe d'Igor Katson et de Michael_Scharf a eu les effets suivants:

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()
6
Rick Mohr

Voici un moyen d’empêcher l’impression du message sur stderr. Juste singe patch la fonction BaseServer.handle_error. Voici comment je le fais:

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()
4
Michael_Scharf

J'ai pu m'en débarrasser en 

proxy_buffering off;

Cela arrête la mise en mémoire tampon des réponses du serveur mandaté. Cela entraîne d'autres problèmes de verrouillage de l'application dorsale pendant longtemps si le client utilise une connexion extrêmement lente.

Pour le rendre conditionnel pour des requêtes particulières, utilisez X-Accel-Buffering = no dans l'en-tête de la réponse.

2
rane

Je suis arrivé avec un patch singe rapide et sale (je ne sais pas s'il supprime les erreurs utiles), qui supprime cette erreur gênante lorsque vous utilisez "./manage.py runserver" ou exécutez des tests LiveServerTestCase.

Il suffit de l'insérer n'importe où dans votre code, là où vous en avez besoin:

# 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
2
Igor Katson

Je l'ai corrigé . Si vous utilisez des liens i.e, balise d'ancrage, dans la page, vous devez faire face au problème "Borken Pipe". Utilisez simplement la balise de lien href = '#'. Ne laissez pas l'attribut href vide. Cela évitera ce type d'erreur. 

0
Gopi Kirupanithi

Je suis également tombé sur ce problème en utilisant tilelite . C'est en fait causé par un bogue connu et maintenant corrigé en python. Vous pouvez résoudre ce problème en appliquant le correctif suivant:

http://bugs.python.org/issue14574

Sinon, vous pouvez télécharger l'une des versions les plus récentes de Python.

0
Jason Huntley