15

Node.js ドメインを使用して例外をキャッチしたいと考えています。これまでのところ動作していますが、例外をキャッチするためにドメインを取得できない場所が 1 つあります。コールバックの例外 2 は、domain.on('error') ハンドラーでキャッチされて処理されますが、例外 1 はキャッチされません。奇妙なことに、例外 1 がスローされたときに、予想どおり 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');
      }
    });
});

例外 2 を実行するために、例外 1 をコメントアウトします。

4

5 に答える 5

18

問題は、 Connect のルーティング中に例外が発生することです。これには、実行の周りtry/catchのブロックと、非運用モードでの実行時にスタック トレースの詳細を出力するデフォルトのエラー ハンドラの両方があります。例外は Express の内部で処理されるため、ドメインが処理する外部レイヤーに到達することはありません。

との違いは、Express を経由した元の呼び出しと同じスタックでexception2、ルートのハンドラー関数が Connect ブロックによって直接実行されることです。'/'2 番目の例外は、一部の I/O 操作が返された後にcallbackで発生するため、ノードのイベント ループ I/O ハンドラーから発生したスタックによって実行されるため、try/catchExpress を使用してその例外を捕捉して保存することはできません。アプリサーバー。実際、すべてのドメインをコメントアウトしてトリップexception2すると、Node.js がクラッシュします。

未処理の例外のみがドメイン メカニズムにルーティングされ、その上に呼び出しスタックが表示されるため、例外は処理され、ドメインには転送されませんexception1try/catch

于 2012-11-05T20:57:54.823 に答える
4

@ユーザー1007983

いいえ、本番環境では、try/catch 処理は引き続き Connect/Express に存在します。これを解決する方法は、「ルート」に独自の try/catch ブロックを追加することです。これを使用して、接続がエラー応答を送信する前にドメインに「エラー」イベントを発行できます。

try {
    // .. code here ..
} catch (err) {
    domain.emit('error', err);
}

それを回避する別の方法は、setImmediate ブロックでコードをラップするなど、ハンドラーから切断することです。

于 2013-06-19T10:10:11.203 に答える
4

Connect-domain を使用すると、express を含む接続モジュールのすべてのエラーをキャッチできます。

接続ドメイン https://github.com/baryshev/connect-domain

express3 の例: http://masashi-k.blogspot.com/2012/12/express3-global-error-handling-domain.html

于 2012-12-21T00:05:43.290 に答える
0

私はtry/catchブロックを試しました (これは、非同期コードで考えているようには機能しない可能性があります)。いくつかの異なる方法でノードドメインを試しました。しかし、サードパーティの lib (sequelize) でスローされた例外を処理できませんでした。例外が発生したのはなぜですか? それは、生成された SQL の形式が適切でなかったためです。(私のせい)。

とにかく、私と私の(小さな)プロジェクトにとって最も効果的な解決策は、foreverを使用することでした。例外が発生するようにしますが、発生した場合はノードを再度起動します。それが最もエレガントなソリューションであるとは思えませんが、私と私の小さなプロジェクトではうまくいきます。

大規模なプロジェクトでは、ドメインをクラスタリング APIと組み合わせることをお勧めします。

ウィンストンは別の選択肢です。foreverwinston と組み合わせて、例外が発生した場合にwinston にメールを送信して、コードを修正できるようにするのはクールかもしれませんその間、forever喜んでアプリを再起動します。

于 2013-10-02T15:52:02.677 に答える
0

ドメインベースのエラー処理をテストしているときに、この問題に遭遇しました。

ここで 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));
于 2014-02-14T14:24:39.513 に答える