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;
}