17

私は現在node.jsアプリに取り組んでおり、通常の非同期コードの問題が発生しています。

NodeのHTTPモジュールの上にサービスサーバーを実装しています。

このサーバーは(エクスプレスライク)ルートをサポートします。たとえば、次のようなコードがあります。

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);
});

ここでエラーをキャッチする方法がわかりません。1つのサーバー側の不具合でサーバーをクラッシュさせたくはありません。代わりに、500を提供したいと思います。

私が思いついた唯一の解決策は、実際には表現力がありません。process.on("uncaughtException",callback)私はノード0.8を使用して同様のコードを使用することを思いついただけですDomains(これは部分的な救済策ですが、ドメインは現在バグがあり、ハンドルごとにドメインを作成する必要があるため、これはまだあまり表現力がありません)。

私が達成したいのはthrow、関数からスコープにアクションをバインドすることです。理想的な解決策は、関数からスローされたすべてのエラーを特定のハンドラー関数にバインドするようなものです。

これは可能ですか?この場合のエラーを処理するためのベストプラクティスは何ですか?

悪いリクエストの後もリクエストを処理し続けることができるはずだということを強調したいと思います。リクエストごとにサーバーを再起動するか、ハンドラーごとにドメインを作成して、キャッチされない例外をキャッチするのは悪い考えのようです。さらに-約束は私を助けることができるかもしれないと聞きました(約束の何かthrow)、約束はこの状況で私を助けることができますか?

4

1 に答える 1

20

警告:ドメインを使用した元の回答はお勧めしません。ドメインは将来廃止される予定です。元の回答を書くのはとても楽しかったですが、あまり関連性がないと思います。代わりに、エラー処理が優れたイベントエミッターとPromiseを使用することをお勧めします。代わりにPromiseを使用した以下の例を示します。ここで使用される約束は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);
});

ソリューションに関するフィードバックをいただければ幸いです。

ちなみに、v 0.8では、ドメインで例外をキャッチすると、まだバブルしprocess.on("uncaughtException")ます。私はこれを自分の中で扱っprocess.on("uncaughtException")

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

ただし、ドキュメントはprocess.on("uncaughtException")いかなる方法に対しても示唆しています

于 2013-01-13T13:43:08.473 に答える