web-dev-qa-db-ja.com

node.jsのクラッシュを防ぐにはどうすればよいですか? try-catchが機能しません

私の経験から、PHPサーバーはログまたはサーバーエンドに例外をスローしますが、node.jsは単にクラッシュします。すべてが非同期に行われるため、コードをtry-catchで囲むことも機能しません。運用サーバーで他の全員が何をしているのか知りたいです。

140
TiansHUo

http://nodejs.org/docs/latest/api/process.html#process_event_uncaughtexception でNode自身のドキュメントを読むことができるため、他の回答は本当に正気ではありません。

誰かが他の記載された回答を使用している場合は、Nodeドキュメントを読んでください:

uncaughtExceptionは例外処理の非常に粗雑なメカニズムであり、将来削除される可能性があることに注意してください。

PM2

まず、PM2Node.jsをインストールすることを強くお勧めします。 PM2は、クラッシュの処理とNodeアプリの監視、および負荷分散に非常に優れています。 PM2は、クラッシュした場合、何らかの理由で停止した場合、またはサーバーが再起動した場合でも、Nodeアプリをすぐに開始します。そのため、コードを管理した後でもアプリがクラッシュした場合、PM2はすぐに再起動できます。詳細については、 PM2のインストールと実行

アプリ自体のクラッシュを防ぐためのソリューションに戻りましょう。

そのため、最後にNodeドキュメント自体が示唆するものを思いつきました。

uncaughtExceptionを使用せず、代わりにdomainsとともにclusterを使用してください。 uncaughtExceptionを使用する場合は、未処理の例外が発生するたびにアプリケーションを再起動してください!

ドメインwithCluster

実際に行うことは、エラーをトリガーしたリクエストにエラー応答を送信し、他のユーザーを通常の時間で終了させ、そのワーカーでの新しいリクエストのリッスンを停止することです。

このように、マスタープロセスはエラーが発生したときに新しいワーカーをフォークできるため、ドメインの使用はクラスターモジュールと連動します。以下のコードを参照して、私が意味することを理解してください

Domainを使用し、Clusterを使用してプログラムを複数のワーカープロセスに分離する復元力を使用することにより、より適切に対応し、エラーをより安全に処理できます。

var cluster = require('cluster');
var PORT = +process.env.PORT || 1337;

if(cluster.isMaster) 
{
   cluster.fork();
   cluster.fork();

   cluster.on('disconnect', function(worker) 
   {
       console.error('disconnect!');
       cluster.fork();
   });
} 
else 
{
    var domain = require('domain');
    var server = require('http').createServer(function(req, res) 
    {
        var d = domain.create();
        d.on('error', function(er) 
        {
            //something unexpected occurred
            console.error('error', er.stack);
            try 
            {
               //make sure we close down within 30 seconds
               var killtimer = setTimeout(function() 
               {
                   process.exit(1);
               }, 30000);
               // But don't keep the process open just for that!
               killtimer.unref();
               //stop taking new requests.
               server.close();
               //Let the master know we're dead.  This will trigger a
               //'disconnect' in the cluster master, and then it will fork
               //a new worker.
               cluster.worker.disconnect();

               //send an error to the request that triggered the problem
               res.statusCode = 500;
               res.setHeader('content-type', 'text/plain');
               res.end('Oops, there was a problem!\n');
           } 
           catch (er2) 
           {
              //oh well, not much we can do at this point.
              console.error('Error sending 500!', er2.stack);
           }
       });
    //Because req and res were created before this domain existed,
    //we need to explicitly add them.
    d.add(req);
    d.add(res);
    //Now run the handler function in the domain.
    d.run(function() 
    {
        //You'd put your fancy application logic here.
        handleRequest(req, res);
    });
  });
  server.listen(PORT);
} 

Domainは廃止予定であり、ノードのドキュメントに記載されているように新しい代替品が提供されると削除されます

このモジュールは廃止予定です。置換APIが完成すると、このモジュールは完全に非推奨になります。ドメインが提供する機能を絶対に必要とするユーザーは、当分の間それに依存する可能性がありますが、将来は別のソリューションに移行する必要があります。

ただし、新しい置換が導入されない限り、Node Documentationが示唆している唯一の優れたソリューションは、ドメインのあるクラスターです。

DomainおよびClusterを深く理解するには

https://nodejs.org/api/domain.html#domain_domainStability: 0 - Deprecated

https://nodejs.org/api/cluster.html

@Stanley Luoに、クラスタとドメインに関するこのすばらしい詳細な説明を共有してくれてありがとう

クラスターとドメイン

122

私はこのコードをrequireステートメントとグローバル宣言のすぐ下に置きました。

process.on('uncaughtException', function (err) {
  console.error(err);
  console.log("Node NOT Exiting...");
});

私のために働く。私がそれについて気に入らない唯一のことは、私がただ物事をクラッシュさせたならば、私がそうするほど多くの情報を得ないことです。

73
hvgotcodes

前述のとおり、 hereerror.stackは、エラーの原因となった行番号など、より完全なエラーメッセージを提供します。

process.on('uncaughtException', function (error) {
   console.log(error.stack);
});
27
Sean Bannister

supervisor を試してください

npm install supervisor
supervisor app.js

または、代わりに forever をインストールできます。

これにより、サーバーが再起動してクラッシュした場合にサーバーを回復できます。

foreverをコード内で使用して、クラッシュしたプロセスを適切に回復できます。

foreverドキュメントには、プログラムによる終了/エラー処理に関する確固たる情報があります。

12
Raynos

Try-catchを使用すると、キャッチされなかったエラーを解決できますが、一部の複雑な状況では、非同期関数をキャッチするなどの仕事を正しく行いません。 Nodeでは、非同期関数呼び出しにアプリのクラッシュ操作が含まれている可能性があることに注意してください。

uncaughtExceptionを使用することは回避策ですが、非効率的であると認識されており、Nodeの将来のバージョンでは削除される可能性が高いため、期待しないでください。

理想的な解決策は、ドメインを使用することです: http://nodejs.org/api/domain.html

サーバーがクラッシュした場合でもアプリが稼働していることを確認するには、次の手順を使用します。

  1. ノードクラスターを使用して、コアごとに複数のプロセスを分岐します。そのため、1つのプロセスが停止した場合、別のプロセスが自動起動します。チェックアウト: http://nodejs.org/api/cluster.html

  2. try-catchまたはuncaughtを使用する代わりに、ドメインを使用して非同期操作をキャッチします。トライキャッチやキャッチが悪い考えだと言っているのではありません!

  3. forever/supervisorを使用してサービスを監視する

  4. デーモンを追加してノードアプリを実行します: http://upstart.ubuntu.com

お役に立てれば!

7
Nam Nguyen

Pm2ノードモジュールを試してみてください。かなり一貫性があり、素晴らしいドキュメントがあります。ロードバランサーが組み込まれたNode.jsアプリのプロダクションプロセスマネージャー。この問題についてはuncaughtExceptionを避けてください。 https://github.com/Unitech/pm2

4

Restifyで素晴らしい動作:

server.on('uncaughtException', function (req, res, route, err) {
  log.info('******* Begin Error *******\n%s\n*******\n%s\n******* End Error *******', route, err.stack);
  if (!res.headersSent) {
    return res.send(500, {ok: false});
  }
  res.write('\n');
  res.end();
});
0
PH Andrade

UncaughtExceptionは「非常に粗雑なメカニズム」で(真)、ドメインは非推奨になりました。ただし、(論理)ドメイン周辺のエラーをキャッチするためのメカニズムが必要です。図書館:

https://github.com/vacuumlabs/yacol

これを行うのに役立ちます。コードを少し書くだけで、コード全体にニースのドメインセマンティクスを設定できます。

0
Tomas Kulich