Hoe debugde ik Fout Econnreset in Node.js?

Ik gebruik een express.js-applicatie met socket.io voor een chat webapp
en ik krijg de volgende fouten willekeurig rond de 24 uur rond 5 uur.
Het knooppuntproces is voor altijd ingepakt en het start zichzelf onmiddellijk opnieuw.

Het probleem is dat het opnieuw opstarten van Express mijn gebruikers uit hun kamers schopt
en niemand wil dat.

De webserver is proxied door haproxy. Er zijn geen socket stabiliteitsproblemen,
Gebruik gewoon WebSockets en Flashsockets Transports.
Ik kan dit niet expres reproduceren.

Dit is de fout met knooppunt 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

bewerken (2013-07-22)

Toegevoegd zowel socket.io clientfout handler en de uncaught exception handler.
Lijkt erop dat deze de fout vangt:

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

Dus ik vermoed dat het geen socket is .IO-probleem maar een HTTP-verzoek aan een andere server
dat ik of een MySQL / Redis-verbinding doe. Het probleem is dat de foutstapel
helpt me niet om mijn CODE-probleem te identificeren. Hier is de log-uitvoer:

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

Hoe weet ik waardoor dit komt? Hoe haal ik meer uit de fout?

Ok, niet erg uitgebreid, maar hier is de stacktrace met 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] ] } }

Hier dien ik het flash socket-beleidsbestand op:

   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)

Kan dit de oorzaak zijn?


Antwoord 1, autoriteit 100%

Je raadt het misschien al: het is een verbindingsfout.

“ECONNRESET”betekent dat de andere kant van het TCP-gesprek het einde van de verbinding abrupt heeft verbroken. Dit is hoogstwaarschijnlijk te wijten aan een of meer fouten in het toepassingsprotocol. Je zou de logboeken van de API-server kunnen bekijken om te zien of deze ergens over klaagt.

Maar aangezien u ook op zoek bent naar een manier om de fout te controleren en mogelijk het probleem op te lossen, moet u eens kijken op Hoe debug je een socket-ophangfout in NodeJS?die op stackoverflow is gepost in verband met een soortgelijke vraag.

Snelle en vuile oplossing voor ontwikkeling:

Gebruik longjohn, je krijgt longstack-traceringen die de asynchrone bewerkingen bevatten.

Schone en correcte oplossing:
Technisch gezien, in node, wanneer je een 'error'-gebeurtenis verzendt en niemand luistert, zal het weggooien. Om ervoor te zorgen dat het niet gooit, zet u er een luisteraar op en handelt u het zelf af. Op die manier kun je de fout loggen met meer informatie.

Als u één luisteraar wilt hebben voor een groep oproepen, kunt u domeinengebruiken en ook andere fouten tijdens runtime. Zorg ervoor dat elke asynchrone bewerking met betrekking tot http(Server/Client) zich in een andere domein-context bevindt naar de andere delen van de code, zal het domein automatisch luisteren naar de error-gebeurtenissen en het doorgeven aan zijn eigen handler. U luistert dus alleen naar die handler en krijgt de foutgegevens. Je krijgt ook gratis meer informatie.

BEWERKEN (2013-07-22)

Zoals ik hierboven schreef:

“ECONNRESET”betekent dat de andere kant van het TCP-gesprek het einde van de verbinding abrupt heeft verbroken. Dit is hoogstwaarschijnlijk te wijten aan een of meer fouten in het toepassingsprotocol. Je zou de logbestanden van de API-server kunnen bekijken om te zien of deze ergens over klaagt.

Wat ook het geval kan zijn: op willekeurige momenten wordt de andere kant overbelast en verbreekt daardoor simpelweg de verbinding. Als dat het geval is, hangt af van waar je precies verbinding mee maakt…

Maar één ding is zeker: je hebt inderdaad een leesfout op je TCP-verbinding die de uitzondering veroorzaakt. Je kunt dat zien door naar de foutcode te kijken die je in je bewerking hebt gepost, die dit bevestigt.


Antwoord 2, autoriteit 15%

Een eenvoudige tcp-server die ik had om het flash-beleidsbestand te bedienen, veroorzaakte dit. Ik kan de fout nu opvangen met een handler:

# 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)

Antwoord 3, Autoriteit 11%

Ik had een soortgelijk probleem waarbij apps eraan begonnen na een upgrade van het knooppunt. Ik geloof dat dit kan worden getraceerd naar knooppunt Release v0.9.10 Dit item:

  • NET: Subress Econnreset (Ben Noordhuis)

Vorige versies zouden geen fout zijn op onderbrekingen van de klant. Een pauze in de verbinding van de klant gooit de fout Econnreset in het knooppunt. Ik geloof dat dit de bedoelde functionaliteit is voor het knooppunt, dus de fix (tenminste voor mij) was om de fout aan te pakken, waarvan ik geloof dat je in niet-gecodeerde uitzonderingen hebt gedaan. Hoewel ik het in de handler van het net.

U kunt dit demonstreren:

Maak een eenvoudige socketserver en krijg knooppunt v0.9.9 en v0.9.10.

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

Start het met V0.9.9 en probeer vervolgens naar FTP naar deze server. Ik gebruik ftp en poort 21 alleen omdat ik op Windows ben en een FTP-client heb, maar geen Telnet Client handig.

Dan van de kant van de client, breek gewoon de verbinding. (Ik doe gewoon CTRL-C)

U zou geen fout moeten zien bij gebruik van knooppunt v0.9.9 en fout bij het gebruik van knooppunt v.0.9.10 en hoger.

In productie gebruik ik v.0.10. iets en het geeft nog steeds de fout. Nogmaals, ik denk dat dit de bedoeling is en de oplossing is om de fout in je code af te handelen.


Antwoord 4, autoriteit 6%

Had vandaag hetzelfde probleem.
Na wat onderzoek vond ik een zeer nuttige --abort-on-uncaught-exceptionnode.js optie. Het biedt niet alleen veel meer uitgebreide en nuttige foutenstacktracering, maar slaat ook het kernbestand op bij een applicatiecrash, waardoor verder debuggen mogelijk is.


Antwoord 5, autoriteit 5%

Ik had hetzelfde probleem, maar ik heb het verholpen door het volgende te plaatsen:

server.timeout = 0;

vóór server.listen. serveris hier een HTTP-server. De standaard time-out is 2 minuten volgens de API-documentatie.


Antwoord 6, autoriteit 4%

Ik krijg ook een ECONNRESET-fout tijdens mijn ontwikkeling, de manier waarop ik dit oplos is door geennodemon te gebruiken om mijn server te starten, gebruik gewoon "node server.js"om start mijn server heeft mijn probleem opgelost.

Het is raar, maar het werkte voor mij, nu zie ik de ECONNRESET-fout nooit meer.


Antwoord 7, autoriteit 3%

Een ander mogelijk geval (maar zeldzaam) zou kunnen zijn als u server-naar-server-communicatie heeft en server.maxConnectionsop een zeer lage waarde hebt ingesteld.

In de kern van het knooppunt net.jshet roept clientHandle.close()aan, wat ook de fout ECONNRESET:

veroorzaakt

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

Antwoord 8, autoriteit 3%

Ja, uw weergave van het beleidsbestand kan zeker de crash veroorzaken.

Als u wilt herhalen, voegt u gewoon een vertraging toe aan uw code:

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

… en gebruik telnetom verbinding te maken met de poort. Als je Telnet loskoppelt voordat de vertraging is verstreken, krijg je een crash (niet-afgevangen uitzondering) wanneer socket.write een fout genereert.

Om de crash hier te voorkomen, voegt u gewoon een fout-handler toe voordat u de socket leest/schrijft:

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

Als je het bovenstaande probeert om de verbinding te verbreken, krijg je alleen een logbericht in plaats van een crash.

En als je klaar bent, vergeet dan niet om de vertraging te verwijderen.


Antwoord 9, autoriteit 2%

Ik had deze fout ook en kon hem oplossen na dagen van debuggen en analyseren:

mijn oplossing

Voor mij was VirtualBox (voor Docker) het probleem. Ik had Port Forwarding geconfigureerd op mijn VM en de fout deed zich alleen voor op de doorgestuurde poort.

algemene conclusies

De volgende observaties kunnen u dagen werk besparen die ik moest investeren:

  • Voor mij deed het probleem zich alleen voor bij verbindingen van localhost naar localhost op één poort. -> controleer of het veranderen van een van deze constanten het probleem oplost.
  • Bij mij deed het probleem zich alleen voor op mijn computer -> laat iemand anders het proberen.
  • Bij mij trad het probleem pas na een tijdje op en kon het niet betrouwbaar worden gereproduceerd
  • Mijn probleem kon niet worden geïnspecteerd met een van de nodes of express (debug-)tools. -> verspil hier geen tijd aan

-> zoek uit of er iets aan de hand is met uw netwerk (-instellingen), zoals VM’s, firewalls enz., dit is waarschijnlijk de oorzaak van het probleem.


Antwoord 10

Ik had dit probleem opgelost door:

  • Mijn wifi-/ethernetverbinding uitschakelen en weer inschakelen.
  • Ik typte: npm updatein terminal om npm bij te werken.
  • Ik heb geprobeerd uit te loggen bij de sessie en opnieuw in te loggen

Daarna probeerde ik hetzelfde npm-commando en het goede was dat het werkte. Ik wist niet zeker of het zo eenvoudig was.

Ik gebruik CENTOS 7


Antwoord 11

Ik heb dit net ontdekt, in ieder geval in mijn geval.

Ik kreeg ECONNRESET. Het bleek dat de manier waarop mijn client was ingesteld, de server een heleboel keer heel snel bereikte met een API-aanroep — en het hoefde maar één keer het eindpunt te bereiken.

Toen ik dat herstelde, was de fout verdwenen.


Antwoord 12

Ik heb het probleem opgelost door simpelweg verbinden met een ander netwerk. Dat is een van de mogelijke problemen.

Zoals hierboven besproken, betekent ECONNRESETdat de TCP-conversatie abrupt het einde van de verbinding verbrak.

Je internetverbinding blokkeert mogelijk de verbinding met sommige servers. In mijn geval probeerde ik verbinding te maken met mLab (clouddatabaseservice die MongoDB-databases host). En mijn ISP blokkeert het.


Antwoord 13

ECONNRESETvindt plaats wanneer de serverzijde de TCP-verbinding sluit en uw verzoek aan de server niet wordt ingewilligd. De server reageert met het bericht dat de verbinding, u verwijst naar een ongeldige verbinding.

Waarom stuurt de server een verzoek met een ongeldige verbinding?

Stel dat je een keep-alive-verbinding tussen client en server hebt ingeschakeld. De keep-alive time-out is ingesteld op 15 seconden. Dit betekent dat als keep-alive 15 seconden inactief is, het een verzoek voor het sluiten van de verbinding zal verzenden. Dus na 15 seconden vertelt de server de client om de verbinding te sluiten. MAAR, wanneer de server dit verzoek verzendt, verzendt de client een nieuw verzoek dat al onderweg is naar de server. Aangezien deze verbinding nu ongeldig is, zal de server weigeren met de ECONNRESET-fout. Het probleem treedt dus op vanwege minder verzoeken aan de serverzijde. Dus schakel keep-alive uit en het zal goed werken.


Antwoord 14

Ik had hetzelfde probleem en het lijkt erop dat de Node.js-versie het probleem was.

Ik heb de vorige versie van Node.js (10.14.2) geïnstalleerd en alles was in orde met nvm (u kunt verschillende versies van Node.js installeren en snel van de ene versie naar de andere overschakelen).

Het is geen “schone” oplossing, maar het kan je tijdelijk van dienst zijn.


Antwoord 15

Node JS-socket is niet-blokkerende io. Overweeg een niet-blokkerende io-verbinding van andere bronnen te gebruiken. Als u bijvoorbeeld een blokkerende Java-socket met node gebruikt, werkt deze slechts enkele seconden, waarna de fout wordt weergegeven. Beperk dit door een niet-blokkerende verbinding te implementeren, d.w.z. socketchannel met de selector.


Antwoord 16

Probeer deze opties toe te voegen aan socket.io:

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

Ik hoop dat dit je zal helpen!

Other episodes