Come posso eseguire il debug dell'errore ECONNRESET in Node.js?


288

Sto eseguendo un'applicazione Express.js utilizzando Socket.io per una webapp di chat e ricevo il seguente errore in modo casuale circa 5 volte durante 24 ore. Il processo del nodo è concluso per sempre e si riavvia immediatamente.

Il problema è che il riavvio di Express espelle i miei utenti dalle loro stanze e nessuno lo vuole.

Il web server è proxy da HAProxy. Non ci sono problemi di stabilità dei socket, semplicemente usando i trasporti di websocket e flashsocket. Non posso riprodurlo apposta.

Questo è l'errore con Nodo v0.10.11:

    events.js:72
            throw er; // Unhandled 'error' event
                  ^
    Error: read ECONNRESET     //alternatively it s a 'write'
        at errnoException (net.js:900:11)
        at TCP.onread (net.js:555:19)
    error: Forever detected script exited with code: 8
    error: Forever restarting script for 2 time

EDIT (22-07-2013)

Aggiunti sia il gestore errori client socket.io che il gestore eccezioni non rilevati. Sembra che questo rilevi l'errore:

    process.on('uncaughtException', function (err) {
      console.error(err.stack);
      console.log("Node NOT Exiting...");
    });

Quindi sospetto che non sia un problema Socket.io ma una richiesta HTTP a un altro server che faccio o una connessione MySQL / Redis. Il problema è che lo stack di errori non mi aiuta a identificare il mio problema con il codice. Ecco l'output del registro:

    Error: read ECONNRESET
        at errnoException (net.js:900:11)
        at TCP.onread (net.js:555:19)

Come faccio a sapere quali sono le cause? Come posso ottenere di più dall'errore?

Ok, non molto prolisso ma ecco lo stacktrace con Longjohn:

    Exception caught: Error ECONNRESET
    { [Error: read ECONNRESET]
      code: 'ECONNRESET',
      errno: 'ECONNRESET',
      syscall: 'read',
      __cached_trace__:
       [ { receiver: [Object],
           fun: [Function: errnoException],
           pos: 22930 },
         { receiver: [Object], fun: [Function: onread], pos: 14545 },
         {},
         { receiver: [Object],
           fun: [Function: fireErrorCallbacks],
           pos: 11672 },
         { receiver: [Object], fun: [Function], pos: 12329 },
         { receiver: [Object], fun: [Function: onread], pos: 14536 } ],
      __previous__:
       { [Error]
         id: 1061835,
         location: 'fireErrorCallbacks (net.js:439)',
         __location__: 'process.nextTick',
         __previous__: null,
         __trace_count__: 1,
         __cached_trace__: [ [Object], [Object], [Object] ] } }

Qui servo il file dei criteri del socket flash:

    net = require("net")
    net.createServer( (socket) =>
      socket.write("<?xml version=\"1.0\"?>\n")
      socket.write("<!DOCTYPE cross-domain-policy SYSTEM \"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd\">\n")
      socket.write("<cross-domain-policy>\n")
      socket.write("<allow-access-from domain=\"*\" to-ports=\"*\"/>\n")
      socket.write("</cross-domain-policy>\n")
      socket.end()
    ).listen(843)

Questa può essere la causa?


3
@GottZ forse questo può aiutare (parlato con qualcuno che lavora all'interno del nodo js) gist.github.com/samsonradu/1b0c6feb438f5a53e30e . Distribuirò oggi il gestore socket.error e ti informerò.
Sansone il

1
@Gottz gli handle socket.error non aiutano, ma process.on ('uncaughtException') rileva l'errore. Ecco il console.log dell'errore: {[Errore: leggi ECONNRESET] codice: 'ECONNRESET', errno: 'ECONNRESET', syscall: 'read'}
Sansone

1
ECONNRESET potrebbe essere un problema di rete. Come sapete, è impossibile rilevare tutte le eccezioni durante i test. Alcuni verranno visualizzati sul tuo server di produzione. Dovrai rendere il tuo server robusto. È possibile gestire l'eliminazione della sessione utilizzando Redis come memoria. Rende persistenti le sessioni anche dopo che il server del nodo si è spento.
user568109

1
Perché questo è legato alla cancellazione della sessione? Sono comunque gestiti da Redis.
Sansone

3
Hai almeno un socket TCP in ascolto che non ha il gestore impostato. Quindi ora è il momento di controllare dove si trova: D
Moss

Risposte:


253

Potresti averlo già indovinato: è un errore di connessione.

"ECONNRESET" significa che l'altro lato della conversazione TCP ha chiuso bruscamente la sua estremità della connessione. Ciò è probabilmente dovuto a uno o più errori del protocollo dell'applicazione. Puoi guardare i log del server API per vedere se si lamenta di qualcosa.

Ma poiché stai anche cercando un modo per controllare l'errore e potenzialmente eseguire il debug del problema, dovresti dare un'occhiata a " Come eseguire il debug di un errore di riaggancio del socket in NodeJS? " Che è stato pubblicato su StackOverflow in relazione a una domanda simile.

Soluzione rapida e sporca per lo sviluppo :

Usa longjohn , ottieni tracce stack lunghe che conterranno le operazioni asincrone.

Soluzione pulita e corretta : tecnicamente, nel nodo, ogni volta che si emette un 'error'evento e nessuno lo ascolta, verrà lanciato . Per non farlo cadere, mettici sopra un ascoltatore e gestiscilo da solo. In questo modo è possibile registrare l'errore con ulteriori informazioni.

Per avere un listener per un gruppo di chiamate è possibile utilizzare domini e rilevare anche altri errori in fase di esecuzione. Assicurati che ogni operazione asincrona relativa a http (Server / Client) sia in un contesto di dominio diverso rispetto alle altre parti del codice, il dominio ascolterà automaticamente gli erroreventi e lo propagherà al proprio gestore. Quindi ascolti solo quel gestore e ottieni i dati di errore. Ottieni anche maggiori informazioni gratuitamente.

EDIT (22-07-2013)

Come ho scritto sopra:

"ECONNRESET" significa che l'altro lato della conversazione TCP ha chiuso bruscamente la sua estremità della connessione. Ciò è probabilmente dovuto a uno o più errori del protocollo dell'applicazione. Puoi guardare i log del server API per vedere se si lamenta di qualcosa.

Quale potrebbe essere anche il caso: in momenti casuali, l'altro lato è sovraccarico e di conseguenza semplicemente uccide la connessione. In tal caso, dipende da cosa ti stai connettendo esattamente ...

Ma una cosa è certa: hai davvero un errore di lettura sulla tua connessione TCP che causa l'eccezione. Puoi vederlo guardando il codice di errore che hai pubblicato nella tua modifica, che lo conferma.


Non deve significare "bruscamente chiuso". Di solito deriva dalla scrittura su una connessione che il peer aveva già chiuso normalmente. Ciò causerà l'emissione di un RST.
Marchese di Lorne,

1
@EJP C'era una buona ragione per cui ho scritto "bruscamente". L'errore (non avviso) indica che la connessione è stata ripristinata dal peer. Una connessione esistente è stata forzatamente chiusa dal peer remoto. Una chiusura forzata è improvvisa poiché inaspettata! (Ciò si verifica normalmente se l'applicazione peer sulla macchina remota viene improvvisamente arrestata, la macchina viene riavviata o l'applicazione peer utilizza una "chiusura forzata" sul socket remoto. Questo errore può anche verificarsi se una connessione veniva interrotta a causa dell'attività di "keep-alive" rilevare un errore mentre una o più operazioni sono in corso ... queste operazioni e le operazioni successive falliranno.)
e-sushi

2
Ottengo questo errore quando invio in batch circa 100 chiamate API quasi contemporaneamente dal browser (Chrome) per il test. Immagino che Chrome debba quindi sovraccaricarsi e uccidere alcune delle connessioni ... @ Sansone - cosa c'è di sbagliato nell'elaborare ogni richiesta nel proprio dominio e rilevare errori di dominio senza riavviare il server?
supershnee,

2
@supershnee Dovresti quasi sempre riavviare il tuo server dopo un'eccezione non rilevata poiché i tuoi dati, l'applicazione e node.js stesso sono in uno stato sconosciuto. Continuare dopo un'eccezione mette a rischio i tuoi dati. Se vuoi saperne di più, dai un'occhiata ai documenti di Node sul processo o ai documenti di Node sui domini .
c1moore,

39

Un semplice server tcp che avevo per servire il file dei criteri flash lo stava causando. Ora posso rilevare l'errore utilizzando un gestore:

# serving the flash policy file
net = require("net")

net.createServer((socket) =>
  //just added
  socket.on("error", (err) =>
    console.log("Caught flash policy server socket error: ")
    console.log(err.stack)
  )

  socket.write("<?xml version=\"1.0\"?>\n")
  socket.write("<!DOCTYPE cross-domain-policy SYSTEM \"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd\">\n")
  socket.write("<cross-domain-policy>\n")
  socket.write("<allow-access-from domain=\"*\" to-ports=\"*\"/>\n")
  socket.write("</cross-domain-policy>\n")
  socket.end()
).listen(843)

2
C'è qualcosa di sbagliato nel codice? Avrei dovuto verificare se il socket è scrivibile prima di scrivere?
Sansone,

Doh, non ho visto che hai già trovato la soluzione prima che io pubblicassi più o meno la stessa cosa :) Per quanto riguarda la tua domanda, anche se controlli che il socket sia scrivibile, potrebbe non esserlo quando ci scrivi microsecondi più tardi e genererebbe ancora un errore, quindi questo è "il modo" per essere sicuri.
Joachim Isaksson il

ok, e c'è una via d'uscita sicura se questo? come socket.close () all'interno del gestore degli errori? perché penso che il mio carico della CPU stia aumentando dopo questi errori (non sono sicuro)
Samson

2
Ho sempre chiamato socket.destroy()il gestore degli errori per essere sicuro. Purtroppo non riesco a trovare la documentazione se è richiesta, ma non emette un errore per farlo.
Joachim Isaksson,

socket.destroy () mi ha salvato la giornata, qualunque cosa funzioni !! Grazie!
Firas Abd Alrahman,

27

Ho avuto un problema simile in cui le app hanno iniziato a errori dopo un aggiornamento di Node. Credo che questo possa essere ricondotto alla versione del nodo v0.9.10 di questo articolo:

  • net: non sopprimere ECONNRESET (Ben Noordhuis)

Le versioni precedenti non avrebbero commesso errori in caso di interruzioni dal client. Un'interruzione della connessione dal client genera l'errore ECONNRESET in Node. Credo che questa sia la funzionalità prevista per Node, quindi la correzione (almeno per me) è stata quella di gestire l'errore, che credo tu abbia fatto in eccezioni non rilevate. Anche se lo gestisco nel gestore net.socket.

Puoi dimostrarlo:

Crea un semplice server socket e ottieni Nodo v0.9.9 e v0.9.10.

require('net')
    .createServer( function(socket) 
    {
           // no nothing
    })
    .listen(21, function()
     {
           console.log('Socket ON')
    })

Avviarlo utilizzando v0.9.9 e quindi provare a FTP su questo server. Sto usando FTP e la porta 21 solo perché sono su Windows e ho un client FTP, ma nessun client Telnet a portata di mano.

Quindi dal lato client, basta interrompere la connessione. (Sto solo facendo Ctrl-C)

Dovresti vedere NESSUN ERRORE quando usi Nodo v0.9.9 ed ERRORE quando usi Nodo v.0.9.10 e successivi.

In produzione, utilizzo v.0.10. qualcosa e dà ancora l'errore. Ancora una volta, penso che questo sia inteso e la soluzione è gestire l'errore nel tuo codice.


3
Grazie, l'ho inchiodato da solo! È importante non consentire la propagazione degli errori in uncaughtException perché rende instabile l'intera app. Ad esempio, dopo aver rilevato circa 10 errori ECONNRESET, il server a volte non rispondeva (si è bloccato e non ha gestito alcuna connessione)
Samson

Sapevo anche della modifica della versione del nodo che non sopprimeva più l'errore, ma vedendo così tanti problemi che si presentavano e venivano risolti ogni versione, preferirei optare per l'ultima. I m utilizzando V0.10.13 ora btw
Samson

16

Ho avuto lo stesso problema oggi. Dopo alcune ricerche ho trovato --abort-on-uncaught-exceptionun'opzione node.js molto utile . Non solo fornisce una traccia dello stack di errori molto più dettagliata e utile, ma salva anche il file core in caso di crash dell'applicazione consentendo un ulteriore debug.


4
strano che una nuova risposta a questa vecchia domanda dovrebbe apparire mentre sto guardando - ma questo è fantastico, grazie
Semicolon

13

Stavo affrontando lo stesso problema ma l'ho mitigato inserendo:

server.timeout = 0;

prima server.listen. serverè un server HTTP qui. Il timeout predefinito è di 2 minuti secondo la documentazione dell'API .


5
Questa non è una soluzione ma piuttosto una soluzione rapida che romperà le cose senza generare un errore.
Nishant Ghodke,

9

Un altro caso possibile (ma raro) potrebbe essere se si dispone di comunicazioni da server a server e si è impostato server.maxConnectionssu un valore molto basso.

Nel core lib net.js del nodo chiamerà clientHandle.close()che causerà anche l'errore ECONNRESET:

if (self.maxConnections && self._connections >= self.maxConnections) {
  clientHandle.close(); // causes ECONNRESET on the other end
  return;
}

Ottima chiamata, ma maxConnectionsil valore predefinito è Infinity. Questo sarebbe il caso (come hai detto tu) se hai esplicitamente ignorato quel valore.
Gajus,

7

Sì, la pubblicazione del file delle politiche può sicuramente causare l'arresto anomalo.

Per ripetere, aggiungi un ritardo al codice:

net.createServer( function(socket) 
{
    for (i=0; i<1000000000; i++) ;
    socket.write("<?xml version=\"1.0\"?>\n");

... e utilizzare telnetper connettersi alla porta. Se si disconnette telnet prima della scadenza del ritardo, si verificherà un arresto anomalo (eccezione non rilevata) quando socket.write genera un errore.

Per evitare il crash qui, basta aggiungere un gestore di errori prima di leggere / scrivere il socket:

net.createServer(function(socket)
{
    for(i=0; i<1000000000; i++);
    socket.on('error', function() { console.log("error"); });
    socket.write("<?xml version=\"1.0\"?>\n");
}

Quando provi la disconnessione sopra, otterrai solo un messaggio di registro invece di un arresto anomalo.

E quando hai finito, ricorda di rimuovere il ritardo.


6

Ricevo anche errore ECONNRESET durante il mio sviluppo, il modo in cui lo risolvo non usando nodemon per avviare il mio server, ma solo "node server.js"per avviare il mio server risolto il mio problema.

È strano, ma ha funzionato per me, ora non vedo più l'errore ECONNRESET.


4

Ho avuto anche questo errore ed è stato in grado di risolverlo dopo giorni di debug e analisi:

la mia soluzione

Per me VirtualBox (per Docker) era il problema. Avevo configurato Port Forwarding sulla mia macchina virtuale e l'errore si verificava solo sulla porta inoltrata.

conclusioni generali

Le seguenti osservazioni possono farti risparmiare giorni di lavoro che ho dovuto investire:

  • Per me il problema si è verificato solo sulle connessioni da localhost a localhost su una porta. -> controllare la modifica di una di queste costanti risolve il problema.
  • Per me il problema si è verificato solo sulla mia macchina -> lascia che qualcun altro lo provi.
  • Per me il problema si è verificato solo dopo un po 'e non è stato possibile riprodurlo in modo affidabile
  • Il mio problema non può essere verificato con nessuno dei nodi o esprime (debug-) strumenti. -> non perdere tempo su questo

-> capire se qualcosa è in disordine con la tua rete (impostazioni), come macchine virtuali, firewall ecc., Questa è probabilmente la causa del problema.


2

Ho risolto il problema semplicemente collegandomi a una rete diversa . Questo è uno dei possibili problemi.

Come discusso in precedenza, ECONNRESET significa che la conversazione TCP ha bruscamente chiuso la sua estremità della connessione.

La tua connessione Internet potrebbe impedirti di collegarti ad alcuni server. Nel mio caso, stavo cercando di connettermi a mLab (servizio di database cloud che ospita database MongoDB). E il mio ISP lo sta bloccando.


Questo ha funzionato per me, il mio codice che funzionava bene poche ore fa improvvisamente ha smesso di funzionare, si scopre, il cambiamento di rete ha causato il problema
Aklank Jain,

2

Ho risolto questo problema con:

  • Disattiva la mia connessione wifi / ethernet e accendi.
  • Ho digitato: npm updatenel terminale per aggiornare npm.
  • Ho provato a disconnettermi dalla sessione e ad accedere di nuovo

Dopo di che ho provato lo stesso comando npm e la cosa buona è che ha funzionato. Non ero sicuro che fosse così semplice.

Sto usando CENTOS 7


0

Ho avuto lo stesso problema e sembra che il problema fosse la versione Node.js.

Ho installato la versione precedente di Node.js (10.14.2) e tutto era ok usando nvm (ti permette di installare diverse versioni di Node.js e passare rapidamente da una versione all'altra).

Non è una soluzione "pulita", ma può servirti temporaneamente.


0

L'ho appena capito, almeno nel mio caso d'uso.

Stavo arrivando ECONNRESET. Si è scoperto che il modo in cui il mio client è stato impostato, colpiva il server con una chiamata API un sacco di volte molto rapidamente - e doveva colpire l'endpoint solo una volta.

Quando l'ho risolto, l'errore era sparito.


-2

Prova ad aggiungere queste opzioni a socket.io:

const options = { transports: ['websocket'], pingTimeout: 3000, pingInterval: 5000 };

Spero che questo ti possa aiutare!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.