PM2を使ってNodeサーバを永続化する

はじめに

当社は以前の記事「Raspberry Pi でWebサーバを立てよう【Node.js】」でNodeサーバを使ったwebシステムを紹介しました。

実はこれには欠点があり、この方法で作ったwebサーバは予期しないエラーが発生したときにサーバ自体が落ちてしまいます。

そんな問題を防ぐために、作ったNodeサーバをPM2で永続化する方法をご紹介したいと思います。

 

PM2とは

PM2はアプリケーションを永続化し、異常終了した場合にアプリケーションの再始動を行ってくれるプロセス管理のアプリケーションです。

また、コンソールの内容を通常時と異常発生時を分けて、自動でログとして保存する機能もあります。

PM2Node監視
PM2Node異常発生時

使い方

まずはコマンドを立ち上げ、PM2をインストールします。

npm install pm2 -g

インストールが完了後、立ち上げたいNodeサーバをpm2コマンドで立ち上げます。

pm2 start app.js  //立ち上げたいNodeサーバ

これで簡単にNodeサーバを永続化させることができます。

永続化したNodeサーバを止める場合には以下のコマンドを入力します。

pm2 stop app.js  //止めたいNodeサーバ

PM2を使ってみる

実際にPM2を使って動かしてみます。

まずはExpress-Generatorを使ってWebサーバを立ち上げます。(参考はこちら)

express testweb --view=pug

routes/index.jsを以下のように書き換えます。

var express = require('express');
var router = express.Router();

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

router.get('/serverdown', async function(req, res, next){
    console.log("start")

    work() //存在しないwork関数を呼び出す 

    res.json({

    })
});
module.exports = router;

これでhttp://localhost:3000/serverdownにアクセスすると、存在しない関数を呼び出してエラーが発生するようになりました。

このサーバをPM2を使って起動した場合と、PM2を使わないで起動した場合でエラーが起きた時の動きを比べてみます。

PM2を使わないで起動した場合

npm startでNodeサーバを起動します。

C:\test_web>npm start

> test-web@0.0.0 start
> node ./bin/www

サーバが起動後にブラウザからhttp://localhost:3000/serverdownにアクセスします。

ブラウザがこのサイトにアクセスできない表示になりました。

ブラウザからhttp://localhost:3000にアクセスしても変わらずページは表示されません。

コンソールを見ると、エラーが表示されサーバが落ちていることが確認できます。

こうなってしまうと再びサーバを起動するまでwebページにアクセスすることはできません。

PM2を使って起動した場合

今度はPM2を使ってwebサーバを立ち上げた場合を試してみます。

先ほど作ったNodeサーバをPM2を使って起動します。

C:\test_web>pm2 start bin/www

[PM2] Spawning PM2 daemon with pm2_home=C:\Users\user\.pm2
[PM2] PM2 Successfully daemonized
[PM2] Starting C:\test_web\bin\www in fork_mode (1 instance)
[PM2] Done.
┌─────┬────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐
│ id  │ name   │ namespace   │ version │ mode    │ pid      │ uptime │ ↺    │ status    │ cpu      │ mem      │ user     │ watching │
├─────┼────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤
│ 0   │ www    │ default     │ 0.0.0   │ fork    │ 11036    │ 0s     │ 0    │ online    │ 0%       │ 30.3mb   │ user     │ disabled │
└─────┴────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘

起動後、同じようにブラウザからhttp://localhost:3000/serverdownにアクセスしてみます。

今度はブラウザがアクセスできない状態にならず、読み込み中のままになります。

その後ブラウザからhttp://localhost:3000にアクセスするとExpressのサンプルページが表示され、正常にアクセスできることが確認できます。

次はコンソールを確認してみますが、PM2でサーバを起動した場合はコンソールにメッセージを出さないのでエラーを確認することはできません。

そこで、PM2が作成するwww-error.logを見るとエラーが発生したことを確認できます。

ReferenceError: work is not defined
    at C:\test_web\routes\index.js:12:5
    at Layer.handle [as handle_request] (C:\test_web\node_modules\express\lib\router\layer.js:95:5)
    at next (C:\test_web\node_modules\express\lib\router\route.js:137:13)
    at Route.dispatch (C:\test_web\node_modules\express\lib\router\route.js:112:3)
    at Layer.handle [as handle_request] (C:\test_web\node_modules\express\lib\router\layer.js:95:5)
    at C:\test_web\node_modules\express\lib\router\index.js:281:22
    at Function.process_params (C:\test_web\node_modules\express\lib\router\index.js:335:12)
    at next (C:\test_web\node_modules\express\lib\router\index.js:275:10)
    at Function.handle (C:\test_web\node_modules\express\lib\router\index.js:174:3)
    at router (C:\test_web\node_modules\express\lib\router\index.js:47:12)

 

PM2を使ったことで、エラーが発生しても再びサーバが起動していることが分かりました。

この動きの中で、http://localhost:3000/serverdownにアクセスしたときにエラーが発生し、一度サーバが落ちて反応を返さなくなり、読み込み中のままになっていました。

その時、PM2がサーバが落ちたのを検知し、サーバを再始動させたのでエラーが起きた後でもhttp://localhost:3000にアクセスするとwebページを見ることができます。

おわりに

PM2を使ってNodeサーバを永続化する方法をご紹介しました。

PM2を使うことでエラーが起きてもサーバが落ちるのを防ぐことができます。

落ちないサーバを作るのが一番ですが、エラーを完全に防ぐことは難しいときもあります。

そういった場合の対策として試してみてはいかがでしょうか。