Обработка асинхронных исключений в Javascript с помощью node.js

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

Я внедряю сервисный сервер поверх HTTP-модуля Node.

Этот сервер поддерживает (экспресс как) маршруты. Например, у меня есть код, который выглядит так:

server.any("/someRoute",function(req,resp){
    resp.end("this text is sent to clients via http")
});

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

server.any("/someRoute",function(req,resp){
    setTimeout(function(){
        throw new Error("This won't get caught");
    },100);
});

Я не понимаю, как я могу поймать ошибку здесь. Я не хочу сбивать сервер из-за одного сбоя на стороне сервера, вместо этого я хочу обслуживать 500.

Единственные решения, которые мне удалось найти, на самом деле не выразительны. Я только придумал с помощью process.on("uncaughtException",callback) и аналогичный код с использованием узла 0,8 Domains (это частичное исправление, но Домены в настоящее время глючат, и это все еще не очень выразительно, так как мне приходится создавать домен для каждого дескриптора).

То, что я хотел бы достичь, является обязательным throw действия от функции к области, идеальное решение - что-то вроде привязки всех сгенерированных ошибок от функции к определенной функции-обработчику.

Это возможно? Как лучше всего обрабатывать ошибки в этом случае?

Я хотел бы подчеркнуть, что он должен иметь возможность продолжать обслуживать запросы после неудачных запросов, и перезагрузка сервера при каждом запросе или создание доменов для каждого обработчика и отлов их необработанных исключений кажутся мне плохой идеей. Кроме того - я слышал, что обещания могут помочь мне (кое-что о throw в обещаниях), может обещания помогут мне в этой ситуации?

1 ответ

Решение

Предупреждение: я бы не рекомендовал исходный ответ с использованием доменов, в будущем домены устарели, мне было очень интересно писать оригинальный ответ, но я больше не считаю его слишком уместным. Вместо этого - я предлагаю использовать источники событий и обещания, которые имеют лучшую обработку ошибок - здесь приведен ниже пример с обещаниями. Обещания, используемые здесь, Bluebird:

Promise.try(function(){ 
    throw new Error("Something");
}).catch(function(err){
    console.log(err.message); // logs "Something"
});

С таймаутом (обратите внимание, что мы должны вернуть Promise.delay):

Promise.try(function() {
    return Promise.delay(1000).then(function(){
        throw new Error("something");
    });
}).catch(function(err){
    console.log("caught "+err.message);
});

С общей функцией NodeJS:

var fs = Promise.promisifyAll("fs"); // creates readFileAsync that returns promise
fs.readFileAsync("myfile.txt").then(function(content){
    console.log(content.toString()); // logs the file's contents
    // can throw here and it'll catch it
}).catch(function(err){
    console.log(err); // log any error from the `then` or the readFile operation
});

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


Я закончил с использованием доменов, я создал следующий файл, который я назвал mistake.js который содержит следующий код:

var domain=require("domain");
module.exports = function(func){
    var dom = domain.create();
    return { "catch" :function(errHandle){
        var args = arguments;
        dom.on("error",function(err){
            return errHandle(err);
        }).run(function(){
            func.call(null, args);
        });
        return this;
    };
};

Вот пример использования:

var atry = require("./mistake.js");

atry(function() {
    setTimeout(function(){
        throw "something";
    },1000);
}).catch(function(err){
    console.log("caught "+err);
});

Это также работает как обычный улов для синхронного кода

atry(function() {
    throw "something";
}).catch(function(err){
    console.log("caught "+err);
});

Буду признателен за отзыв о решении

Кстати, в версии 0.8 очевидно, что когда вы ловите исключение в домене, оно все еще всплывает process.on("uncaughtException"), Я имел дело с этим в моем process.on("uncaughtException") с

 if (typeof e !== "object" || !e["domain_thrown"]) {

Тем не менее, документация предлагает против process.on("uncaughtException") тем не мение

Другие вопросы по тегам