Не удалось обработать исключение с доменами node.js, используя выражение - программирование
Подтвердить что ты не робот

Не удалось обработать исключение с доменами node.js, используя выражение

Я хочу использовать Node.js Домены для исключения исключений. Он работает до сих пор, но есть одно место, в котором я не могу получить домены, чтобы поймать исключение. exception2 в обратном вызове захватывается и обрабатывается в обработчике domain.on('error'), но исключение1 не попадает. Странно то, что при исключении exception1 он не отключается Node, как я ожидал. Вот пример моего приложения:

var domain = require('domain');
var request = require('request');
var express = require('express');

var serverDomain = domain.create();
serverDomain.on('error', function(err) {
  console.log("Server Domain Error: " + err);
});

var app;

serverDomain.run(function() {
  app = express();
  app.listen(3000);
});

app.use(function(req, res, next) {

  var reqDomain = domain.create();
  reqDomain.add(req);
  reqDomain.add(res);
  reqDomain.on('error', function(err) {
    console.log("Req Domain Error: " + err);
    reqDomain.dispose();
    next(err);
  });

  next();
});

app.get('/', function(req, res) {
  var uri = "http://google.com";

  exception1.go();

  request.get({url:uri, json: {}},
    function (error, response, body) {
      if(response.statusCode === 200) {
        exception2.go();
        res.send('Success getting google response');
      }
    });
});

Чтобы выполнить exception2, я закомментирую исключение 1.

4b9b3361

Ответ 1

Проблема заключается в том, что исключение происходит во время Подключить маршрутизацию, у которого есть как try/catch блок вокруг его выполнения, а также обработчик ошибок по умолчанию, который выводит данные трассировки стека при работе в непроизводственном режиме. Поскольку исключение обрабатывается внутри Express, оно никогда не достигает вашего внешнего уровня для обработки доменов.

Как он отличается от exception2 заключается в том, что функция обработчика для маршрута '/' выполняется непосредственно этим блоком Connect в том же стеке, что и исходный вызов, который прошел через Express. Второе исключение возникает в обратном вызове после того, как какая-то операция ввода-вывода вернулась и, следовательно, выполняется стеком, происходящим из обработчика ввода-вывода цикла событий Node, и поэтому try/catch Express не доступен для блокировки это исключение и сохранить сервер приложений. Фактически, если вы закомментируете весь материал домена и отпустите exception2, он выйдет из строя Node.

Так как только необработанные исключения направляются в механизм домена, а поскольку exception1 имеет try/catch, видимый в нем стек вызовов выше него, исключение обрабатывается и не пересылается в домен.

Ответ 3

@user1007983

Нет, в производстве обработка try/catch все еще существует в Connect/Express. Способ его решения состоит в том, чтобы добавить свой собственный блок try/catch в "root", который затем вы можете использовать, чтобы выпустить событие "ошибка" в домен, прежде чем соединение отправит ответ об ошибке.

try {
    // .. code here ..
} catch (err) {
    domain.emit('error', err);
}

Другой способ обойти это просто отсоединить от обработчика, например, обернуть ваш код в блоке setImmediate

Ответ 4

Я пробовал блокировать try/catch (что может не работать так, как вы думаете, с асинхронным кодом). Я пробовал node домены несколькими способами. Но я не смог обработать исключение, брошенное в стороннюю lib (sequelize). Почему я получил исключение? Ну, это потому, что SQL, который был сгенерирован, не был хорошо сформирован. (Моя ошибка).

Anywho, решение, которое наилучшим образом помогло мне и моему (маленькому) проекту, заключалось в использовании forever, Пусть исключения произойдут, но запустите node, если они это сделают. Я сомневаюсь, что это самое элегантное решение, но оно работает для меня и моего небольшого проекта.

При использовании более крупного проекта областью, объединенной с API кластеризации, может быть хорошим выбором.

Winston - еще один выбор. Было бы здорово совместить forever с winston, так что если вы получите исключение, вы можете winston отправить вам по электронной почте, чтобы вы могли исправить код. Тем временем forever с радостью перезапустит приложение для вас.

Ответ 5

Я столкнулся с этой проблемой при проверке обработки ошибок на домене.

Я пошел с подходом, предложенным здесь Issac, с несколькими незначительными изменениями: используйте "domain.active", чтобы получить текущий активный домен и испустить событие ошибки, и я использовал функцию обертки, чтобы избежать необходимости изменить все мои функции обработчика:

domainWrapper = function(func) {
    return function(req, res) {
        try {
            return func(req, res);
        } catch (err) {
            domain.active.emit('error', err);
        }
    }
}

Затем изменилось такое:

app.get('/jobs', handlerFunc);

:

app.get('/jobs', domainWrapper(handlerFunc));