Как стать автором
Обновить

Комментарии 21

Для express`а (connect) есть модуль connect-domain.
var connectDomain = require('connect-domain');
 ...
var app = express();
 ...
// Подключаем middleware
app.use(connectDomain());  
// Обработка исключений.
app.use(function(err, req, res, next) {
      logger.error(err);
      res.send(500, 'Houston, we have a problem!\n');
  });
В ноде всегда было это:
 process.on('uncaughtException', function (err) { ... }); 

Что не давала падать приложению из за ошибки. Проблема в том что этот обработчик не дает возможности обработать ошибку там где она случилась, поэтому и были изобретены domain'ы
Это плохая практика. Мы теряем контекст при такой обработке. Можно использовать только в очень небольшом количестве сценариев.
Все правильно, но это было единственное средство не дать приложению упасть полностью.

Домены дали возможность обрабатывать исключения более управляемо, разделяя ошибки по уровням, то есть не просто не упасть на одном запросе, а еще и отследить и обработать эту ошибку.
Надеюсь, я выучу Scala быстрее, чем весь мир начнет писать на node.js
Будете компилировать программы на scala дольше, чем люди пишут код на js.
долго запрягает, да быстро едет.
Классная штука домены, но плюс к ним для отказоустойчивости не помешает:

root@server:/usr/local/server# cat ./server.js

#!/usr/bin/node
process.on('uncaughtException', function (err)
  console.log(err);
});

...

root@server:/usr/local/server# chmod +x /usr/local/server/server.js

# например под upstart:

root@server:/usr/local/server# cat /etc/init/server.conf

description     "My super server"

start on runlevel [2345]
stop on runlevel [016]

respawn

exec NODE_ENV="production" /usr/local/server/server.js 2>&1 >> /var/log/server/server.log

# for production:
root@server:/usr/local/server# service server start 
root@server:/usr/local/server# tail -f /var/log/server/server.log

# for development:
root@server:/usr/local/server# ./server.js
Спасибо, очень лаконичный конфиг, удобно.
Обрабатывать ошибки как в вашем примере не рекомендуется самими разработчиками Node. О чем явно написано в той же документации по ссылке.

В двух словах: после перехвата исключения, процесс находится в непредсказуемом состоянии, поэтому рекомендуется завершить обработку текущих запросов на этом воркере, завершить процесс и запустить новый воркер. Пример там есть.
#5114 — тут есть эпичное обсуждение проблем на эту тему. Топикстартер — автор модуля trycatch, о котором я писал на хабре.

Также вот тут был интересный эксперимент на тему того, как заставить работать вложенные домены в версии 0.8. Печальное зрелище :)
Кстати, в каких типичных случаях приложение может кинуть исключение в асинхронном вызове не по вине программиста? На сколько я знаю, все популярные библиотеки пробрасывают ошибки первым аргументом в callback, разве что JSON.parse() в try/catch приходится оборачивать. Есть еще какие-нибудь юзкейсы?
Кидают исключения, например синхронные функции в модулях fs, path, и т.д. Кто даст гарантию, что они не вызываются из асинхронного кода?

А чуть менее популярные библиотеки? К сожалению, мы не можем поручиться за всех, и это становится принципиальной проблемой — как обезопасить себя от библиотеки, которая, вероятно, ведет себя не так?
Это похоже на обертку try{}catch{} только с красивым синтаксисом.
Тоже сначала так показалось. Но фишка в том, что оно из callback-ов ловит исключения. Я правда по исходнику так и не понял каким образом они ловятся. А вообще, почему в таком коде pastebin.com/cix7GvjF, 'free exception' попадает то в один domain, то в другой, то вообще в uncachedException вываливается? Это же полный атас. Вы уж простите, но проще Erlang выучить.
Как заметил выше товарищ Nailgun: «после перехвата исключения, процесс находится в непредсказуемом состоянии». Соответственно, лучше не использовать такой юзкейс.
НЛО прилетело и опубликовало эту надпись здесь
Есть хороший мини модуль node-domain-middleware для express, написанный моим коллегой. Пример кода с исользованием его и okay

var ok = require('okay');
app.use(require('express-domain-middleware'));
app.use(app.router);
app.use(function errorHandler(err, req, res, next) {
  console.log('error on request %d %s %s: %j', process.domain.id, req.method, req.url, err);
  res.send(500, "Something bad happened. :(");
});
app.get('/error', function(req, res, next) {
  db.query('SELECT happiness()', ok(next, function(rows) {
    fs.readFile('asldkfjasdf', ok(next, function(contents) {
      process.nextTick(ok(next, function() {
        throw new Error("The individual request will be passed to the express error handler, and your application will keep running.");
      }));
    }));
  }));
});


я хотел промолчать… честно.
Хм… знатоки ES6 расскажите, я правильно понимаю, что с появлением генераторов можно будет писать так:

try {
  var res = yield asyncCall();
} catch (e) {
  logger.log(e);
}


и это решит все проблемы с обработкой асинхронных ошибок?
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации