Comments 11
Спасибо!
0
Хорошо-бы еще добавить nodejs.org/api/process.html#process_event_uncaughtexception про перехват глобальных исключений, где можно также получить и код возврата — а не уронив активный инстанц нода (не забываем про модуль cluster)
И по поводу кода — для синхронных функций принято выбрасывать exception для try/catch, а для асинхронных возвращять результат вида prototype function(err=true, object=ExceptionObject)
Также в node.js+express есть одна особенность — если Вы НЕ уверены в том что Вам всегда завершится удачно — то нужно на каждое подключение в текущем контексте создавать таймер (обычно на 15секунд) — который автоматически закроет соединение при бездействии — тем самым очищая хвосты дескрипторов (актуально при больших нагрузках).
И по поводу кода — для синхронных функций принято выбрасывать exception для try/catch, а для асинхронных возвращять результат вида prototype function(err=true, object=ExceptionObject)
Также в node.js+express есть одна особенность — если Вы НЕ уверены в том что Вам всегда завершится удачно — то нужно на каждое подключение в текущем контексте создавать таймер (обычно на 15секунд) — который автоматически закроет соединение при бездействии — тем самым очищая хвосты дескрипторов (актуально при больших нагрузках).
-2
То что Вы описали — набор совершенно разных тематик. Не для одной статьи точно. В данной статье рассматривался именно способ обработки ошибок из асинхронных вызовов без потери контекста запроса и без ручной передачи ошибки наверх по стеку вызовов. Поэтому ни process.on('uncaughtException') ни возврат ошибки первым параметров в калбек тут не подходят. Об этом я упомянул в статье.
Самый простой пример, когда описанный в статье метод актуален:
1. Поступает запрос на страницу новостей
2. Контроллер запрашивает у модели новостей список первой страницы новостей
3. После того как список получен другой метод модели должен сопоставить каждой новости автора (они хранятся в отдельной таблице)
4. Во время получения информации об одном из авторов падает СУБД и запрос выполняется с ошибкой.
В самом простом случае нам нужно показать ошибку 500 пользователю и выполнить служебные действия — оповещение администраторов, запись в лог.
В случае с передачей ошибки первым параметром, нам придётся сначала вернуть её в в калбек функции получения авторов, потом вернуть её оттуда в функцию получения новостей, оттуда уже в функцию контроллера, в которой есть контекст ответа и уже оттуда мы можем вызвать next(err) и передать её обработчику ошибок. Очень часто бывает что стек вызовов ещё больше и появляется куча однотипного кода.
Описанный в статье метод позволяет избавиться от ручной передачи ошибки. Достаточно сделать throw err; там где она произошла и ошибка будет передана в обработчик с сохранением контекста запроса.
Самый простой пример, когда описанный в статье метод актуален:
1. Поступает запрос на страницу новостей
2. Контроллер запрашивает у модели новостей список первой страницы новостей
3. После того как список получен другой метод модели должен сопоставить каждой новости автора (они хранятся в отдельной таблице)
4. Во время получения информации об одном из авторов падает СУБД и запрос выполняется с ошибкой.
В самом простом случае нам нужно показать ошибку 500 пользователю и выполнить служебные действия — оповещение администраторов, запись в лог.
В случае с передачей ошибки первым параметром, нам придётся сначала вернуть её в в калбек функции получения авторов, потом вернуть её оттуда в функцию получения новостей, оттуда уже в функцию контроллера, в которой есть контекст ответа и уже оттуда мы можем вызвать next(err) и передать её обработчику ошибок. Очень часто бывает что стек вызовов ещё больше и появляется куча однотипного кода.
Описанный в статье метод позволяет избавиться от ручной передачи ошибки. Достаточно сделать throw err; там где она произошла и ошибка будет передана в обработчик с сохранением контекста запроса.
+2
У меня вот давно возник вопрос. Какие плюсы есть у NodeJS по сравнению с Java?(тут намеренно сравнение инструмента и языка программирования, но можно взять например Netty чтобы было всё честно). Ответьте мне кто-нибудь пожалуйста.
0
Это очень холиварный вопрос. Серебряной пули не существует. У каждой технологии есть свои плюсы и минусы. Важно только то, как их использовать. На любой озвученный плюс найдётся Java/Python/Erlang/Ruby/C# программист, который скажет, что на %language_name% это можно сделать ещё лучше. Смысла нет это обсуждать.
+2
У нас с Вами сходятся интересы :)
habrahabr.ru/company/alawar/blog/158905/
Раз уж вы работали с доменами, не подскажете, как можно создать 2 вложенных домена, и сделать rethrow, чтобы ошибка попала из обработчика ошибок внутреннего в обработчик ошибок внешнего? Я пытался с ними экспериментировать, но с некоторыми вопросами так и не разобрался.
habrahabr.ru/company/alawar/blog/158905/
Раз уж вы работали с доменами, не подскажете, как можно создать 2 вложенных домена, и сделать rethrow, чтобы ошибка попала из обработчика ошибок внутреннего в обработчик ошибок внешнего? Я пытался с ними экспериментировать, но с некоторыми вопросами так и не разобрался.
0
groups.google.com/d/msg/nodejs/i8NjWjVvk2I/K7grylhIDywJ — это единственный рабочий способ?
0
Я не задавался вопросом вложенных доменов. Для решения необходимых задач пока хватает описанного в статье метода. Сейчас ради интереса попробовал — с ходу оно не заработало. uncaughtException работает, но в документации этот механизм не рекомендуют использовать вообще. Как рабочий вариант — вызывать topDomain.emit('error', err) внутри функции обработки ошибки вложенного domain. Но вообще, вкладывать Domain друг в друга, наверное, не самая лучшая идея. По крайней мере для этого сначала нужно полностью разобраться в их внутреннем устройстве, чтобы быть уверенным, что это не окажет влияния на производительность.
0
Ну просто вложенные домены — это прямой аналог try-catch блоков.
Ну и модули control-block и trycatch, которые решают сходные задачи, вполне себе переносят вложенность.
Ну и модули control-block и trycatch, которые решают сходные задачи, вполне себе переносят вложенность.
0
Я протестировал скорость работы модуля trycatch, на простейшем примере он работает на 20-30% медленнее чем вариант с Domain. При этом вариант с Domain работает на 7-10% медленнее варианта без обработчика ошибок вообще. И это на простейшем примере. trycatch работает очень хардкорно. Он оборачивает все системные методы в свои обработки и следит за стеком выполнения. Это очень медленные операции. К сожалению, пока нет времени протестировать на более сложном примере, но есть мнение что разрыв в скорости будет увеличиваться с возрастанием кол-ва операций. Плюс ко всему цена ошибки в стороннем модуле, который изменяет поведение всех важнейших методов очень высока.
control-block не подходит для решения поставленной задачи, т.к. требует дополнительно оборачивать калбеки.
Коды тестов:
Тестировал утилитой ab.
control-block не подходит для решения поставленной задачи, т.к. требует дополнительно оборачивать калбеки.
Коды тестов:
Тест без обработки ошибок (эталон)
var
connect = require('connect');
var app = connect()
.use(function(req, res){
process.nextTick(function() {
res.end('Hello from Connect!');
});
})
.use(function(err, req, res, next) {
res.end(err.message);
});
app.listen(3131);
Тест connect-domain без выстреливания ошибки
var
connect = require('connect'),
connectDomain = require('connect-domain');
var app = connect()
.use(connectDomain())
.use(function(req, res){
process.nextTick(function() {
res.end('Hello from Connect!');
});
})
.use(function(err, req, res, next) {
res.end(err.message);
});
app.listen(3131);
Тест connect-domain с выстреливанием ошибки
var
connect = require('connect'),
connectDomain = require('connect-domain');
var app = connect()
.use(connectDomain())
.use(function(req, res){
process.nextTick(function() {
if (Math.random() > 0.5) {
throw new Error('Asynchronous error from process.nextTick');
} else {
res.end('Hello from Connect!');
}
});
})
.use(function(err, req, res, next) {
res.end(err.message);
});
app.listen(3131);
Тест trycatch без выстреливания ошибки
var
connect = require('connect'),
trycatch = require('trycatch');
var app = connect()
.use(function (req, res, next) {
trycatch(function () {
next();
}, function (err) {
next(err);
});
})
.use(function (req, res){
process.nextTick(function () {
res.end('Hello from Connect!');
});
})
.use(function (err, req, res, next) {
res.end(err.message);
});
app.listen(3131);
Тест trycatch с выстреливанием ошибки
var
connect = require('connect'),
trycatch = require('trycatch');
var app = connect()
.use(function (req, res, next) {
trycatch(function () {
next();
}, function (err) {
next(err);
});
})
.use(function (req, res){
process.nextTick(function () {
if (Math.random() > 0.5) {
throw new Error('Asynchronous error from process.nextTick');
} else {
res.end('Hello from Connect!');
}
});
})
.use(function (err, req, res, next) {
res.end(err.message);
});
app.listen(3131);
Тестировал утилитой ab.
+1
Sign up to leave a comment.
Обработка асинхронных ошибок с сохранением контекста запроса в connect/express