Не удалось обработать исключение с доменами 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.
Ответы
Ответ 1
Проблема заключается в том, что исключение происходит во время Подключить маршрутизацию, у которого есть как try/catch
блок вокруг его выполнения, а также обработчик ошибок по умолчанию, который выводит данные трассировки стека при работе в непроизводственном режиме. Поскольку исключение обрабатывается внутри Express, оно никогда не достигает вашего внешнего уровня для обработки доменов.
Как он отличается от exception2
заключается в том, что функция обработчика для маршрута '/'
выполняется непосредственно этим блоком Connect в том же стеке, что и исходный вызов, который прошел через Express. Второе исключение возникает в обратном вызове после того, как какая-то операция ввода-вывода вернулась и, следовательно, выполняется стеком, происходящим из обработчика ввода-вывода цикла событий Node, и поэтому try/catch
Express не доступен для блокировки это исключение и сохранить сервер приложений. Фактически, если вы закомментируете весь материал домена и отпустите exception2
, он выйдет из строя Node.
Так как только необработанные исключения направляются в механизм домена, а поскольку exception1
имеет try/catch
, видимый в нем стек вызовов выше него, исключение обрабатывается и не пересылается в домен.
Ответ 2
Подключить-домен позволяет обнаруживать все ошибки для подключаемых модулей, включая экспресс.
Connect-домен
https://github.com/baryshev/connect-domain
Пример для express3:
http://masashi-k.blogspot.com/2012/12/express3-global-error-handling-domain.html
Ответ 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));