Node js ECONNRESET
Я запускаю приложение Express js с socket.io для чата webapp, и я получаю следующую ошибку случайным образом около 5 раз в течение 24h. Процесс node завернут навсегда и перезапускается непосредственно.
Проблема в том, что перезапуск экспресс выкидывает моих пользователей из своих комнат и никто этого не хочет.
Веб-сервер проксируется HAProxy. Нет проблем со стабилизацией сокета, просто используя переносы веб-портов и флеш-карт. Я не могу воспроизвести это специально.
Это ошибка с node 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 (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)
Может ли это быть причиной?
Ответы
Ответ 1
Простой сервер tcp, который я использовал для работы с файлом политики Flash, вызывал это. Теперь я могу уловить ошибку с помощью обработчика:
# 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
Возможно, вы уже догадались: это ошибка соединения.
"ECONNRESET" означает, что другая сторона протокола TCP резко закрыла конец соединения. Это, скорее всего, связано с одной или несколькими ошибками протокола приложения. Вы можете посмотреть журналы сервера API, чтобы узнать, не жалуется ли что-нибудь.
Но так как вы также ищете способ проверить ошибку и потенциально отладить проблему, вы должны взглянуть на Как отладить ошибку зависания сокета в NodeJS? ", который был отправлен в stackoverflow по отношению к аналогичному вопросу.
Быстрое и грязное решение для разработки:
Используйте longjohn, вы получите длинные трассировки стека, которые будут содержать операции async.
Чистое и правильное решение: Технически, в node, когда вы выпустите событие 'error'
, и никто его не слушает, он будет генерировать. Чтобы он не бросал, поставьте на него слушателя и обработайте его самостоятельно. Таким образом, вы можете зарегистрировать ошибку с дополнительной информацией.
Чтобы иметь одного слушателя для группы вызовов, вы можете использовать домены, а также уловить другие ошибки во время выполнения. Убедитесь, что каждая операция async, связанная с http (Server/Client), находится в другом контексте domain по сравнению с другими частями кода, доменом будет автоматически прослушивать события error
и будет распространять его на свой собственный обработчик. Поэтому вы только слушаете этого обработчика и получаете данные об ошибках. Вы также можете получить дополнительную информацию бесплатно.
EDIT (2013-07-22)
Как я писал выше:
"ECONNRESET" означает, что другая сторона протокола TCP резко закрыла конец соединения. Это, скорее всего, связано с одной или несколькими ошибками протокола приложения. Вы можете посмотреть журналы сервера API, чтобы узнать, не жалуется ли что-нибудь.
Что может быть и так: в случайные моменты другая сторона перегружена и просто убивает соединение в результате. Если это случай, зависит от того, к чему вы подключаетесь точно...
Но одно точно: у вас действительно есть ошибка чтения в вашем TCP-соединении, которое вызывает исключение. Вы можете видеть это, посмотрев код ошибки, который вы опубликовали в своем редактировании, что подтверждает его.
Ответ 3
У меня была аналогичная проблема, когда приложения начали выходить из строя после обновления Node. Я считаю, что это можно проследить до Node release v0.9.10 этого пункта:
- net: не подавлять ECONNRESET (Ben Noordhuis)
Предыдущие версии не будут выходить из строя при прерываниях от клиента. Разрыв в соединении с клиентом вызывает ошибку ECONNRESET в Node. Я полагаю, что это предназначенная функция для 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)
При использовании Node v0.9.9 и ERROR при использовании Node v.0.9.10 и выше вы должны видеть NO ERROR.
В производстве я использую v.0.10. что-то, и это все еще дает ошибку. Опять же, я думаю, что это предназначено, и решение заключается в обработке ошибки в вашем коде.
Ответ 4
Я столкнулся с той же проблемой, но я смягчил ее, поставив:
server.timeout = 0;
до server.listen
. server
- это HTTP-сервер. Тайм-аут по умолчанию составляет 2 минуты в соответствии с документацией по API.
Ответ 5
Сегодня у нас была такая же проблема.
После некоторых исследований я нашел очень полезную --abort-on-uncaught-exception
node.js вариант. Мало того, что он обеспечивает гораздо более многословную и полезную трассировку стека ошибок, но также сохраняет файл ядра при сбое приложения, что позволяет продолжить отладку.
Ответ 6
Да, ваша служба файла политики может привести к сбою.
Чтобы повторить, просто добавьте задержку в свой код:
net.createServer( function(socket)
{
for(i=0; i<1000000000; i++);
socket.write("<?xml version=\"1.0\"?>\n")
…
... и используйте telnet
для подключения к порту. Если вы отключите telnet до истечения времени задержки, вы получите крах (неперехваченное исключение), когда 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")
Когда вы попробуете вышеуказанное отсоединение, вы получите сообщение журнала вместо сбоя.
И когда вы закончите, не забудьте удалить задержку.
Ответ 7
Другим возможным случаем (но редким) может быть, если у вас есть связь между сервером и сервером, и установите server.maxConnections
на очень низкое значение.
В node core lib net.js он вызовет clientHandle.close()
, который также вызовет ошибку ECONNRESET:
if (self.maxConnections && self._connections >= self.maxConnections) {
clientHandle.close(); // causes ECONNRESET on the other end
return;
}