PM2 使った感じ
◆ 高機能だけど登録の概念が無いのだけが使いづらいところ
watch
マウントしてると node-dev で変更監視できなかったので デーモン化などいろいろしてくれる高機能な PM2 だともしかしたら と思って一応試してみましたすると
10569 [2018-08-29T11:10:00.855Z] PM2 error: Error: ENOSPC: no space left on device, watch '/mnt/windows/tmps/fw/laravel/vendor/jakub-onderka/php-console-c
10569 olor/src/JakubOnderka/PhpConsoleColor'
10570 at FSWatcher.start (fs.js:1375:26)
10571 at Object.fs.watch (fs.js:1412:11)
10572 at createFsWatchInstance (/home/nm2exp/.config/yarn/global/node_modules/chokidar/lib/nodefs-handler.js:37:15)
10573 at setFsWatchListener (/home/nm2exp/.config/yarn/global/node_modules/chokidar/lib/nodefs-handler.js:80:15)
10574 at FSWatcher.NodeFsHandler._watchWithNodeFs (/home/nm2exp/.config/yarn/global/node_modules/chokidar/lib/nodefs-handler.js:232:14)
10575 at FSWatcher.NodeFsHandler._handleDir (/home/nm2exp/.config/yarn/global/node_modules/chokidar/lib/nodefs-handler.js:414:19)
10576 at FSWatcher.<anonymous> (/home/nm2exp/.config/yarn/global/node_modules/chokidar/lib/nodefs-handler.js:462:19)
10577 at FSWatcher.<anonymous> (/home/nm2exp/.config/yarn/global/node_modules/chokidar/lib/nodefs-handler.js:467:16)
10578 at FSReqWrap.oncomplete (fs.js:150:5)
10579 [2018-08-29T11:10:00.856Z] PM2 error: Error: ENOSPC: no space left on device, watch '/mnt/windows/tmps/fw/laravel/vendor/jakub-onderka/php-console-c
10579 olor/tests/JakubOnderka/PhpConsoleColor'
10580 at FSWatcher.start (fs.js:1375:26)
10581 at Object.fs.watch (fs.js:1412:11)
10582 at createFsWatchInstance (/home/nm2exp/.config/yarn/global/node_modules/chokidar/lib/nodefs-handler.js:37:15)
10583 at setFsWatchListener (/home/nm2exp/.config/yarn/global/node_modules/chokidar/lib/nodefs-handler.js:80:15)
10584 at FSWatcher.NodeFsHandler._watchWithNodeFs (/home/nm2exp/.config/yarn/global/node_modules/chokidar/lib/nodefs-handler.js:232:14)
10585 at FSWatcher.NodeFsHandler._handleDir (/home/nm2exp/.config/yarn/global/node_modules/chokidar/lib/nodefs-handler.js:414:19)
10586 at FSWatcher.<anonymous> (/home/nm2exp/.config/yarn/global/node_modules/chokidar/lib/nodefs-handler.js:462:19)
10587 at FSWatcher.<anonymous> (/home/nm2exp/.config/yarn/global/node_modules/chokidar/lib/nodefs-handler.js:467:16)
10588 at FSReqWrap.oncomplete (fs.js:150:5)
こういう感じのすごい量のエラーが一気にでました
何も起きないのかと思ったらログにディスクスペースがないエラーがいっぱいです
しかもよくみたら watch 対象が全く関係ないフォルダです
マウントしてるフォルダは Linux で動かしたいもの全部入りなので Node.js 以外にも PHP の laravel とか Python のあれこれとかあるのですがそういう関係ないフォルダでエラーが出てるようです
どうして関係ないフォルダまで watch しようとしてるのか不明ですが 動かないだけじゃなくエラーまで出るので PM2 の watch はマウント環境で使わないほうが良さそうです
基本的な使い方
ドキュメントを見てるとけっこういろいろコマンドがあって複雑なのですが 単に起動や停止する分には複雑なことはなかったですドキュメントは古いのと新しいのがあって 古いのを開くと新しいのに案内されますが古いほうが情報が多いようです
機能が消えてるわけでもないのに古い方にはあるのに新しい方だと消えてるものがあったりします
以下の○○ って書いてるのに以下が存在しなかったりとかです
なにするもの
そういえばちゃんと書いてなかったのでここで書きますPM2 という名前が Process Manager の略らしいです
名前の通りプロセス管理してくれるものです
node dir/app.js
と実行するのを
pm2 start dir/app.js
と書けます
これにする意味の一つはバックグラウンドで動かしてくれることです
ウェブサーバを起動してるときに別の操作をしたいときにバックグラウンドで実行してくれるのは便利です
byobu や tmux とかはこういうときに便利ですが コマンドによっては表示が壊れるのであまり使いたくないこともあります
ちなみに pm2 の list や monit は byobu でやるとまともに見れませんでした
コマンドの最後に & をつけてバックグラウンド実行でもいいですが これをすると他の作業中に標準出力が混ざってきます
ファイルへのリダイレクトにできますがファイルの管理も少し面倒です
それにリモートでつないでるときに切断してしまうと jobs のリストにでないです
jobs の番号で kill したり fg → Ctrl-C とはいかないです
「pkill node」 とやってたのですが node コマンドが複数動いてるときもあるのでそういうときに困ります
そういう いろいろがあるので管理してくれるツールに任せてしまうとちょっと楽になれます
他には エラーで終了したときに自動で再起動もしてくれます
個人用じゃなくてちゃんとしたサービスとかに使うなら必要な機能です
開発中だとシンタックスエラーとかで無限ループしそうですがたしかデフォルトで 15 回エラーになったら止まったはずです
起動してるののみ管理される
リストに起動中とか停止中とかそういう表示なので systemd 的なものを想像していたのですが登録するという概念がないようです
起動=登録です
登録のみというのができません
簡単に使えるように先に登録だけしておいて まだ起動はしないということはできないようです
登録してあると情報が取得できたり 名前で操作できます
登録されていないと起動するファイルを指定することになって 登録済みと未登録で操作方法が変わります
また PM2 自体を終了させて 何かのコマンドで起動すると 前の状態は残らずクリアな状態で起動されます
リストは空です
save と resurrect コマンドを使って 保存と復元をするのですが 復元すると 実行状態は維持されず復元時にすべて実行されます
PM2 を終了する前に停止してるのはリストから除外して save コマンドを実行しないと実行中のものだけを維持できません
リストから除外してしまうと起動するのにまたスクリプト名の指定が必要ですし OS 自体を再起動したときには対処できません
実行状態を管理というよりデーモン化してエラーが起きても止まらずバックグラウンドで動かしてくれるツール程度に考えたほうがいいかもしれないです
systemd に登録できる
OS 起動時の自動起動には対応しています起動時には resurrect が実行されます
なので上で書いたように適切に save しないと実行状態は維持されません
自動起動は systemd が使われます
fedora の場合なので 別ディストリビューションだとそれ用のツールになります
user1@fedora-server ~/t/03> cat /etc/systemd/system/pm2-user1.service
[Unit]
Description=PM2 process manager
Documentation=https://pm2.keymetrics.io/
After=network.target
[Service]
Type=forking
User=user1
LimitNOFILE=infinity
LimitNPROC=infinity
LimitCORE=infinity
Environment=PATH=/home/user1/n/bin:/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
Environment=PM2_HOME=/home/user1/.pm2
PIDFile=/home/user1/.pm2/pm2.pid
ExecStart=/home/user1/.config/yarn/global/node_modules/pm2/bin/pm2 resurrect
ExecReload=/home/user1/.config/yarn/global/node_modules/pm2/bin/pm2 reload all
ExecStop=/home/user1/.config/yarn/global/node_modules/pm2/bin/pm2 kill
[Install]
WantedBy=multi-user.target
こういう設定ファイルが作られます
設定するには startup コマンドを管理者権限で実行します
God Daemon
PM2 の何かのコマンドを実行すると PM2 デーモンがバックグラウンド起動しますps でみてみると
PM2 v3.0.4: God Daemon
のような名前のプロセスが存在するはずです
PM2 のコマンドの操作ではこのデーモンにアクセスして情報を取得したりします
止めるときは kill コマンドです
God Daemon を停止する前に実行中のスクリプトはすべて停止されます
pm2 start app.js
pm2 list
pm2 kill
pm2 list
の順に実行すれば上で書いた毎回クリアされるというのが確認できます
最後の list では何も実行されていないです
ログは console.log の延長
ログが思ったよりしっかりしていて ローテートまでできるみたいで期待したのですが あくまで console.log の延長みたいです標準出力と標準エラー出力を保存してるだけなので 自分で出し分けたりできません
デバッグ用に多くの情報表示するけど保存期間は少なめなもの 情報は少ないけど長く保存しておきたいもの とかファイルを分けられないです
ユーザ入力が間違ってるパターンのエラーとバグが原因の想定外のエラーを分けるのも難しそうです
単純にサーバを起動してアクセスがあったアクセスログを別にしたいというのですらできなそうです
そういう特別な別ファイルにログしたいなら別にロガーを使った方がいいのかもしれません
設定ファイル
登録だけはできず起動してるものしか管理できないと書きましたが 設定ファイルを使うと少し改善できますinit コマンドでサンプルのファイルが作られます
ecosystem.config.js というファイル名で 設定情報が書かれたオブジェクトをエクスポートする JavaScript のファイルです
module.exports = {
apps : [
{
name: "main-app",
script: "main/app.js",
},
{
name: "sub-app",
script: "sub/app.js",
}
],
}
これだけでもおっけいです
ここに書いておくと
pm2 start --only main-app
のように名前を使って実行できます
only がないとファイルに書いた全部が起動するのでひとつだけなら only で指定します
こう書けるのは ecosystem.config.js という名前のファイルがカレントディレクトリにある場合のみで 別のパスの場合は指定が必要です
pm2 start pm2-apps.config.js --only main-app
プログラムから操作
pm2 を require すればプログラムからも操作できますデーモン化しているので 停止したいときは pm2 を操作する必要があります
process.exit しても再起動されてしまいます
接続してスクリプトを起動して 1 秒後に停止して切断するという処理はこう書けます
const util = require("util")
const pm2 = require("pm2")
!async function(){
const connect_info = await util.promisify(pm2.connect.bind(pm2))()
const start_info = await util.promisify(pm2.start.bind(pm2))({script: "x.js", name: "app"})
await util.promisify(fn => setTimeout(() => fn(), 1000))()
const stop_info = await util.promisify(pm2.stop.bind(pm2))("app")
pm2.disconnect()
}()
catch できない
プログラムから操作してみて少し困ったのですが キャッチできないエラーがあります> const pm2 = require("pm2")
undefined
> try{ pm2.stop({ name: "", script: "" }, (...args) => console.log(1)) } catch(err){ console.log(2) }
undefined
> TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received type object
// 略
stop に間違った引数で start のようなオブジェクトを渡すとエラーになりますが try では受け取れません
エラー情報が入ってコールバック関数が呼び出されるはずなのにコールバック関数も呼び出されていません
Promise 使わず非同期実行するとエラー時のコールバック関数の呼び出し漏れが使う側に影響するので 困るところです
ダウンロード数って結構適当
公式サイトのダウンロード数をみてるとすごくスピードで増えてますhttps://pm2.io/runtime/
さすがに早すぎない?と思ったのとこんな頻度で更新するために通信をページ開いてるユーザ全員からってけっこう大変そうなので 実際のダウンロード数じゃなさそうと思ってソース覗いてみました
!function e() {
setTimeout(function() {
t.todayDownloads++,
t.totalDownloads++,
e()
}, Math.floor(1300 * Math.random() + 200))
}();
だそうです