Узел 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 для запуска приложения узла. В моем случае это не проблема.
Несколько вариантов, которые я пробовал и работали как временные решения
- Если вы используете узел, попробуйте переключиться между разными версиями узла, используя
node use #version#
. Работал на меня - Попробуйте переключить подключение к Интернету
В моем случае проблема была в версии. Приложение выдало ошибку ECONNRESET сv16.14.2
но с ним все работало нормальноv18.16.0
. Я использую n для управленияnode
версии.
Попробуйте добавить эти параметры в socket.io:
const options = { transports: ['websocket'], pingTimeout: 3000, pingInterval: 5000 };
Я надеюсь, что это поможет вам!