Узел JS ECONNRESET

Я запускаю приложение Express js с socket.io для веб-приложения чата, и в течение 24 часов случайно получаю следующую ошибку примерно 5 раз. Процесс узла заворачивается навсегда и сразу же перезапускается.

Проблема в том, что перезапуск экспресса выгоняет моих пользователей из их комнат, и никто не хочет этого.

Веб-сервер прокси HAProxy. Нет проблем со стабильностью сокетов, только использование веб-сокетов и транспортов flashsockets. Я не могу воспроизвести это специально.

Это ошибка с узлом 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

РЕДАКТИРОВАТЬ (2013-07-22)

Добавлен как клиентский обработчик ошибок socket.io, так и обработчик необработанных исключений. Кажется, что этот ловит ошибку:

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

Поэтому я подозреваю, что это не проблема socket.io, а запрос http к другому серверу, который я делаю, или соединение mysql / redis. Проблема в том, что стек ошибок не помогает мне определить мою проблему с кодом. Вот вывод журнала:

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

Откуда я знаю, что вызывает это? Как я могу получить больше от ошибки?

Хорошо, не очень многословно, но вот трассировка стека с помощью "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] ] } }

Здесь я использую файл политики флэш-сокета:

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)

Может ли это быть причиной?

19 ответов

Решение

Это было вызвано простым tcp-сервером, который я имел для обслуживания файла политики флэш-памяти. Теперь я могу поймать ошибку с помощью обработчика:

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

Возможно, вы уже догадались: это ошибка подключения.

"ECONNRESET" означает, что другая сторона диалога TCP внезапно закрыла свой конец соединения. Скорее всего, это связано с одной или несколькими ошибками протокола приложения. Вы можете просмотреть журналы сервера API, чтобы увидеть, если он жалуется на что-то.

Но так как вы также ищете способ проверить ошибку и, возможно, отладить проблему, вы должны взглянуть на " Как отладить ошибку зависания сокета в NodeJS? ", Которая была опубликована в stackru по аналогичному вопросу.

Быстрое и грязное решение для разработки:

Используйте longjohn, вы получите длинные трассировки стека, которые будут содержать асинхронные операции.

Чистое и правильное решение: Технически, в узле, всякий раз, когда вы излучаете 'error' событие и никто его не слушает, оно бросит. Чтобы он не бросался, поместите слушателя в него и разберитесь с этим сами. Таким образом, вы можете записать ошибку с дополнительной информацией.

Чтобы иметь одного прослушивателя для группы вызовов, вы можете использовать домены, а также ловить другие ошибки во время выполнения. Убедитесь, что каждая асинхронная операция, связанная с http (сервер / клиент), находится в другом доменном контексте, по сравнению с другими частями кода, домен автоматически прослушивает error события и будет распространять его в свой собственный обработчик. Таким образом, вы только слушаете этот обработчик и получаете данные об ошибках. Вы также получите больше информации бесплатно.

РЕДАКТИРОВАТЬ (2013-07-22)

Как я уже писал выше:

"ECONNRESET" означает, что другая сторона диалога TCP внезапно закрыла свой конец соединения. Скорее всего, это связано с одной или несколькими ошибками протокола приложения. Вы можете просмотреть журналы сервера API, чтобы увидеть, если он жалуется на что-то.

Что может также иметь место: в случайное время другая сторона перегружается и в результате просто разрывает соединение. Если это так, все зависит от того, к чему вы подключаетесь.

Но одна вещь наверняка: у вас действительно есть ошибка чтения на вашем соединении TCP, которое вызывает исключение. Это можно увидеть, посмотрев код ошибки, который вы опубликовали в своем редактировании, что подтверждает это.

У меня была похожая проблема, когда приложения начинали выдавать ошибки после обновления Node. Я считаю, что это можно отследить до выпуска Node v0.9.10 этого элемента:

  • нет: не подавлять ECONNRESET (Бен Noordhuis)

Предыдущие версии не допускали ошибок при прерываниях от клиента. Разрыв соединения с клиентом выдает ошибку ECONNRESET в узле. Я полагаю, что это предназначенная функциональность для Node, поэтому исправление (по крайней мере, для меня) заключалось в обработке ошибки, которую, я полагаю, вы сделали в исключениях UnCaught. Хотя я справляюсь с этим в обработчике net.socket.

Вы можете продемонстрировать это:

Сделайте простой сервер сокетов и получите Node v0.9.9 и v0.9.10.

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

Запустите его, используя v0.9.9, а затем попытайтесь подключиться к этому серверу по FTP. Я использую FTP и порт 21 только потому, что нахожусь в Windows и у меня есть FTP-клиент, но клиент telnet не пригодится.

Тогда со стороны клиента просто разорвите соединение. (Я просто делаю Ctrl-C)

Вы должны увидеть NO ERROR при использовании Node v0.9.9 и ERROR при использовании Node v.0.9.10 и выше.

В производстве я использую v.0.10. что-то и все равно выдает ошибку. Опять же, я думаю, что это предназначено, и решение состоит в том, чтобы обработать ошибку в вашем коде.

Была такая же проблема сегодня. После некоторых исследований я нашел очень полезный --abort-on-uncaught-exception опция node.js Он не только обеспечивает более подробное и полезное отслеживание стека ошибок, но также сохраняет основной файл при сбое приложения, позволяя дальнейшую отладку.

Я также получаю сообщение об ошибке ECONNRESET во время своей разработки. Я ее решаю, не используя nodemon для запуска моего сервера, просто использую "node server.js" чтобы начать мой сервер исправил мою проблему.

Это странно, но это сработало для меня, теперь я больше никогда не вижу ошибку ECONNRESET.

Я столкнулся с той же проблемой, но я смягчил ее, разместив:

server.timeout = 0;

до server.listen, server здесь HTTP-сервер Время ожидания по умолчанию составляет 2 минуты согласно документации API.

Да, ваша подача файла политики может определенно вызвать сбой.

Повторим, просто добавьте задержку в ваш код:

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

... и использовать telnet подключиться к порту. Если вы отключите telnet до истечения задержки, вы получите сбой (исключение uncaught), когда socket.write выдает ошибку.

Чтобы избежать сбоя, просто добавьте обработчик ошибок перед чтением / записью сокета:

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

Когда вы попробуете описанное выше отключение, вы получите сообщение журнала вместо сбоя.

И когда вы закончите, не забудьте убрать задержку.

Другой возможный случай (но редкий) может быть, если у вас есть связь между серверами и установлен server.maxConnections до очень низкого значения.

В ядре узла lib net.js это вызовет clientHandle.close() что также приведет к ошибке ECONNRESET:

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

ECONNRESET происходит, когда сторона сервера закрывает TCP-соединение и ваш запрос к серверу не выполняется. Сервер отвечает сообщением, что соединение, вы имеете в виду недопустимое соединение.

Почему сервер отправляет запрос с неверным подключением?

Предположим, вы включили постоянное соединение между клиентом и сервером. Таймаут проверки активности настроен на 15 секунд. Это означает, что если keep-alive бездействует в течение 15 секунд, он отправит запрос на закрытие соединения. Таким образом, через 15 секунд сервер говорит клиенту закрыть соединение. НО , когда сервер отправляет этот запрос, клиент отправляет новый запрос, который уже находится в полете, на конец сервера. Поскольку сейчас это соединение недействительно, сервер отклонит сообщение с ошибкой ECONNRESET. Таким образом, проблема возникает из-за меньшего количества запросов к серверу. Поэтому, пожалуйста, отключите keep-alive, и все будет нормально.

У меня тоже была эта ошибка, и я смог ее решить после нескольких дней отладки и анализа:

мое решение

Для меня VirtualBox (для Docker) был проблемой. На моей виртуальной машине настроена переадресация портов, и ошибка произошла только на перенаправленном порту.

общие выводы

Следующие наблюдения могут сэкономить вам дни работы, которые мне пришлось потратить:

  • Для меня проблема возникла только при подключении от localhost к localhost на одном порту. -> проверка изменения любой из этих констант решает проблему.
  • Для меня проблема возникла только на моей машине -> пусть кто-то другой попробует.
  • Для меня проблема возникла только через некоторое время и не может быть надежно воспроизведена
  • Моя проблема не может быть проверена ни одним из узлов или выражений (отладки). -> не трать время на это

-> выяснить, если что-то не так с вашей сетью (-настройки), такие как виртуальные машины, брандмауэры и т. д., это, вероятно, причина проблемы.

Я решил проблему, просто подключившись к другой сети. Это одна из возможных проблем.

Как обсуждалось выше, ECONNRESET означает, что диалог TCP внезапно закрыл свой конец соединения.

Возможно, ваше интернет-соединение не позволяет подключиться к некоторым серверам. В моем случае я пытался подключиться к mLab (облачной службе баз данных, в которой размещены базы данных MongoDB). И мой провайдер блокирует это.

Я решил эту проблему:

  • Отключить соединение Wi-Fi/ Ethernet и включить.
  • Я набрал: npm update в терминале обновить npm.
  • Я попытался выйти из сеанса и войти снова

После этого я попробовал ту же команду npm, и хорошо, что она сработала. Я не был уверен, что это так просто.

Я использую CENTOS 7

Я только что понял это, по крайней мере, в моем случае использования.

Я получал ECONNRESET. Оказалось, что мой клиент был настроен так, что он много раз обращался к серверу с вызовом API очень быстро - и ему нужно было только один раз попасть в конечную точку.

Когда я исправил это, ошибка исчезла.

У меня была такая же проблема, и похоже, что проблема была в версии Node.js.

Я установил предыдущую версию Node.js (10.14.2), и с помощью nvm все было в порядке (позволяет установить несколько версий Node.js и быстро переключаться с одной версии на другую).

Это не "чистое" решение, но оно может служить вам временно.

Сокет Node JS не блокирует io. Рассмотрите возможность использования неблокирующего io-соединения из других источников. Например, если вы используете блокирующий сокет Java с узлом, он будет работать только в течение нескольких секунд, после чего будет выдана ошибка. Смягчить это, реализовав неблокирующее соединение, то есть socketchannel с селектором.

Сначала я запускаю свое приложение, я получаю ECONNRESET , после чего я получаю ошибку вроде ECONNREFUSED . Я столкнулся с обеими этими проблемами при запуске приложения node . Для обеих проблем я обнаружил, что это происходит из-за того, что не запущен wampserver . Я использую базу данных mysql в своем приложении для получения данных с помощью wampserver. Я разрешаю это, запуская wampserver, а затем запуская приложение node . Он работает нормально. Вы можете использовать node или nodemon для запуска приложения узла. В моем случае это не проблема.

Несколько вариантов, которые я пробовал и работали как временные решения

  1. Если вы используете узел, попробуйте переключиться между разными версиями узла, используяnode use #version#. Работал на меня
  2. Попробуйте переключить подключение к Интернету

В моем случае проблема была в версии. Приложение выдало ошибку ECONNRESET сv16.14.2но с ним все работало нормальноv18.16.0. Я использую n для управленияnodeверсии.

Попробуйте добавить эти параметры в socket.io:

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

Я надеюсь, что это поможет вам!

Другие вопросы по тегам