◾️ はじめに
プロダクトでプリンター機能を実装する際、プリンターサーバー(Node.jsアプリ)を常時起動し続ける必要がありました。
しかし、普通にNode.jsを起動するだけではターミナルを閉じるとプロセスが死んでしまいます。
そこでPM2を導入しました!
本記事ではPM2の仕組みから導入方法、実際のコマンドまでまとめました。
◾️ PM2とは
PM2(Process Manager 2)はNode.jsのプロセスマネージャーです。
簡単に言うと、Node.jsアプリをバックグラウンドで常時稼働させ、クラッシュしても自動で再起動してくれるツールです。
◾️ PM2でできること
1. プロセスの永続化
ターミナルを閉じてもアプリが動き続けます。
2. 自動再起動
アプリがクラッシュすると自動で再起動します。pm2 status の ↺ の数字が再起動回数です。
3. ログ管理
アプリの標準出力・エラーをファイルに保存します。
~/.pm2/logs/アプリ名-out.log # 標準出力
~/.pm2/logs/アプリ名-error.log # エラー
4. 複数プロセス管理(クラスターモード)
同じアプリを複数プロセスで起動してアクセスを分散できます。
pm2 start index.ts -i 4 # 4プロセスで起動
5. ホットリロード(ゼロダウンタイム更新)
クラスターモード時にサービスを止めずにコードを更新できます。
pm2 reload myapp
1プロセスずつ順番に入れ替えるので、常にサービスが動き続けます。
6. メモリ制限で自動再起動
pm2 start index.ts --max-memory-restart 300M
7. リアルタイムモニタリング
pm2 monit
◾️ PM2の仕組み
プロセスとは
プロセスとは実行中のプログラムのことです。
プログラム(ファイル)は設計図で、それを実行したときにメモリ(RAM)上に展開されて動いている状態がプロセスです。
引き出し(SSD)にしまってあるindex.ts
↓
作業机(RAM)に広げて実行 = プロセス
↓
電源オフ → 机の上が全部消える
↓
でもSSDのindex.tsは残ってる
親子プロセスの関係
PM2は親プロセスとして動き、アプリを子プロセスとして起動します。
【普通の起動】
ターミナル → node index.ts
ターミナルを閉じる → index.tsも死ぬ
【PM2経由の起動】
ターミナル → PM2(デーモン) → index.ts
ターミナルを閉じる → PM2は生きてる → index.tsも生きてる
クラッシュをどうやって検知しているか
ポーリング(定期監視)ではなく、OSのイベント駆動で検知しています。
PM2はNode.jsのAPIを使って子プロセスにイベントリスナーを登録します。
child.on('exit', (code) => {
// プロセスが死んだら再起動する
})
プロセスが終了するとOSが即座にPM2に通知し、PM2がほぼ瞬時に再起動します。
index.tsがクラッシュ
↓
OSが終了シグナルを検知(即座)
↓
PM2に通知(即座)
↓
PM2が再起動(ほぼ瞬時)
終了コード
プロセスが終了するときOSは終了コードを返します。
| 終了コード | 意味 |
|---|---|
| 0 | 正常終了 |
| 1以上 | エラーで終了 |
PM2は終了コードを見て再起動するか判断します。
PC再起動後の復元
PCの電源が切れるとRAM上のプロセスは全て消えます。
pm2 save # 現在のプロセス情報をdump.pm2に保存
PC再起動 # 全プロセスが死ぬ
pm2 resurrect # dump.pm2を読み込んで同じプロセスを再起動
保存場所:~/.pm2/dump.pm2
◾️ 導入方法
インストール
npm install -g pm2
基本的な起動
pm2 start index.ts --name myapp
TypeScriptの場合
pm2 start src/index.ts --name myapp --interpreter node --interpreter-args "--import tsx"
状態を保存してPC再起動後も自動復元
pm2 save
タスクスケジューラー(Windows)でPC起動時に以下を実行するよう設定します。
pm2 resurrect
◾️ ターミナルを閉じた場合の挙動まとめ
| 状況 | PM2デーモン | プロセス |
|---|---|---|
| ターミナルを閉じる | 生きてる | 生きてる |
pm2 stop |
生きてる | 死ぬ |
pm2 kill |
死ぬ | 死ぬ |
| PC再起動 | 死ぬ | 死ぬ |
◾️ 最後に
PM2を導入することで、プリンターサーバーをターミナルを閉じても、クラッシュしても安定して稼働させることができました。
特に、今回のユースケースでは以下が重要でした!
-
--nameでプロセス名を指定してログを管理しやすくする -
pm2 save+ タスクスケジューラーでPC再起動後も自動復元 - ログは
~/.pm2/logs/に自動で保存されるので障害調査に役立つ