読者です 読者をやめる 読者になる 読者になる

Node.jsの例外処理(承前:なぜ例外処理が必要なのか)

ドメインの実装を徘徊してだいたい裏がとれたので、一旦まとめ。
JavaScriptの言語仕様として例外処理は用意されています。すなわち、何か処理上で継続しがたいような不都合があったら、throw文にて例外を送出します。(脱線:JavaScript例外としては一般にErrorオブジェクトが用意されているので、throw new Error('Message'); とすればいいのですが、ここはErrorじゃなくても良い。私は面倒なとき、単なる文字列を投げたりよくしています。throw 'ダメぽ'; みたいに)その例外は、コールスタックをBubblingしてtry-catch文で保護されたブロックまで遡り、catch文を実行したのち、呼び出し行の次の処理ブロック/行へ移ります。このとき一切try-catchに出会わなければシステム終了。これはこれで正しい。設計として例外が送出されたら確実にアプリケーションが死んでもらわないとダメな場合があるのです。初期設定で問題があったのに握りつぶして何事も無かったかのように動かれてしまうと、ユーザー向けサービス開始後まで問題が発覚しないので。
一方でWEBサーバでリクエスト毎に「たまたま」外部状況等が悪くて仕様どおりにサービスができないとき、リクエスト毎にサーバが落ちてしまっては継続サービスにならないために例外の捕捉は必須ですし、さらには例外を握りつぶさずにきちんとユーザー向けエラー表示をして終わらせないといけません。たとえばTwitterのクジラ画面はTwitterの中で何か問題が起きているために、ユーザーが期待するTwitterのサービスが利用できない状況になってます。問題は起きないことを求められますが、それでも問題が起きてちゃっているならば、問題を通知することを言い訳に、まあしばらく後で来てよ、と苦境をユーザーに説明して個別の問題については白黒つけちゃうのです。これをやらないとブラウザが真っ白で固まる状態になり、それはユーザーのブラウザがハングってるのか、接続回線に不都合があるのか、はたまたサーバの提供回線が貧弱なのか、例外が発生したのか、ユーザーはわからない。何か努力するものなのか、復旧をお祈りするしかないのかわからない。適切な例外処理戦術はアプリケーションにとってとても重要です。
というところで、じゃあNode.jsもJavaScriptだし、言語仕様通りにtry-catchすればいいのかというと、Node.jsはそれだけだと足りないんです。

// 例外が捕捉できてる
function fireError() {
    throw 'fireError()';
}

try {
    fireError();
} catch(e) {
    console.log('catch: ' + e);
}

これ、ちゃんと例外処理されています。意図通り「catch: fireError()」ってコンソールに出る。でもNode.js特有の次の書き方だと例外が捕捉されない。

// 例外捕捉できない
try {
    process.nextTick(fireError);
} catch(e) {
    console.log('catch: ' + e);
}

次もダメ。

// 例外捕捉できない
try {
    setTimeout(fireError, 0);
} catch(e) {
    console.log('catch: ' + e);
}

これを解決するためにドメインの存在意義があるのでした。パターンは限られます。Node.js特有のイベント処理ループ内で処理を遅延させたときです。

続く...