記事一覧に戻る

【PM2】エラーで落ちたプログラムを自動で再起動させる方法

はじめに

私は2021年度にはじめて仮想通貨の自動取引をBOTを作成しました。

これまで自分のデスクトップ上で動く簡易なアプリは作ったことはありましたが、Web API等を使った本格的(?)なプログラムを作ったのは初めてでしたし、何よりお金が儲かる可能性も秘めているということもあってか、当時の私は24時間ぶん回してやろうといきり立っていたのでした。FXや株取引と違って、仮想通貨は平日だろうと祝日だろうと、仮24時間365日間取引が可能なので、変なヤル気に満ちていました。

満を持してさくらのVPSでサーバを借り、万全の態勢でリリースしたのですが、、、 ポジションを持ったままエラー落ちし、本来の損切りラインを超えたままホールドしてしまうことが多発しました。 (当然、逆に利確ラインを超えた持ち続けることも起こりうる訳ですが、何故か1回も起こりませんでした。人生とはそんなものです。)

もちろんエラーがあまり出ないようにコーディングするのも大事ですが、、、ネットワーク関連の不調とか、自分では制御できない部分でエラーになることもありました。

なるべく止まらないよう、エラーは例外扱いするようにツギハギしていったら、今度はバグ取りが難しくなってしまいました。エラーとして表示されず、ヒントが無いから当然ですね。。。

そこで私は思った訳です。

この世の中には無数のwebサイトがあって、中には止まったら凄まじい損失が出るものも多数あるはずだ、、、。それがエラーで落ちてしまった時に、この高度に発展した資本主義社会を構成する企業が、その損失を黙って受け入れるわけがないと、、、。自動で再起動する仕組みが絶対にあるはずだ、、、世の中のweb上のサービスは、実質ゾンビに違いないのだと。

PM2について

調べたらすぐ見つかりました。PM2というNode.jsのパッケージです。主にExpress.jsやDjango等で構築した、Webサーバアプリでよく使われるようです。当然、Webサーバでなくても自動取引BOTにでも使えます。

npmのリポジトリを見ると、以下のように紹介されています。

PM2 is a production process manager for Node.js applications with a built-in load balancer. It allows you to keep applications alive forever, to reload them without downtime and to facilitate common system admin tasks.

Goolgle翻訳

PM2 は、組み込みのロード バランサーを備えた Node.js アプリケーションの生産プロセス マネージャーです。アプリケーションを永久に存続させ、ダウンタイムなしで再ロードし、一般的なシステム管理タスクを容易にすることができます。

いろいろ多機能なので、試していない機能もあるのですが、エラーで落ちたものを自動で再起動させるだけなら、とても簡単です。なんでみんなもっと早く教えてくれないの?と思ったくらいです。

何気に、コマンドラインで実行した時にバックグラウンドで実行してくれるのも便利です。ログを確認するために新たにコマンドプロンプトを起動するといった手間もなくなります。

ちなみに、引用部分はNode.jsのアプリのみに言及されていますが、別の言語のプログラムにも対応しています。リンク先にPM2起動例のところに、*You can start any application(Node.js,Python,Ruby,binaries in $PATH...)*と記載されています。

ちなみに私のBOTもPythonですがPM2でゾンビ化しています。

インストール方法

PM2自体はNode.jsのアプリですので、Node.js(12.1以降)がインストールされている必要があります。

サーバにはもうNode.jsもPM2のインストールされているので、今手元にあるChromebookでPM2をインストールしてみようと思います。 まずは環境と何が入っているか確認してみます。

ChromebookのLinux仮想環境はこんな感じ。

PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"

Node.jsは過去インストールしていたようです。

node-version

グローバルにインストールしていたパッケージはこんな感じ。

global-packages

下地は整っているでしょう。 PM2をnpmのリポジトリに従ってインストールしていきます。グローバルにインストールですね。

sudo npm install pm2 -g

パーミッションのエラーが出たのでsudoを入れて実行しています。

v5.2.2が入りました。

install-pm2

アプリを起動

5秒ごとに"Hello,world."をコンソールに出力し、その後エラーで落ちるテスト用のスクリプトを作成しました。これをPM2で起動させ、ゾンビ化されているか確認してみます。

# test-pm2.py
import time

while True:
    time.sleep(5)
    print("Hello,wold.")
    raise Exception("stopping...")

初回起動のコマンドpm2 start 実行ファイル名です。今回の実行ファイルはtest-pm2.pyです。

pm2 start test-pm2.py

こんなエラーが出てしまいました。

[PM2][ERROR] Interpreter python is NOT AVAILABLE in PATH. (type `which python` to double check.)

私のChromebookだとpython3でパスが通っているのに、pythonで実行しようとしてエラーになっているのでしょうか。

--interpreterオプションでpython3を指定したら問題なく動きました。

pm2 start test-pm2.py --interpreter python3
lauching-python

name列にアプリ名(test-pm2)が表示されています。初回起動以降、止めたり、再起動したりする際にこのアプリ名を使用します。今回は指定していませんが、初回起動時にpm2 start test-pm2.py --name 任意の名前のように指定することも可能です。

動作確認

標準出力やエラー出力はPM2がファイルにログ出力してくれます。

想定通り永続化してくれているなら、標準出力ログには「Hello,world」がずらーっと並び、 エラー出力ログにはエラーのメッセージとともに、「stopping...」がずらーっと並んでいるはずです。

ログの中身はpm2 logs アプリ名で確認できます。

pm2 logs test-pm2
logs

※画像ではpm2 logと打っていますが、logでもlogsでも動きます。前者は、コマンドを打ったタイミングにログファイルに出力されているものしか表示されませんが、後者はリアルタイムで出力されたログも表示してくれるようです(chatGPT情報)。

標準出力ログ、エラー出力の順番に表示されていますが、どちらも想定通り出力されてますね。ゾンビ化成功です。

ちなみに、デフォルトだと、標準出力、エラー出力ともに最後の15行が表示されます。増やしたい場合はlinesパラメータに指定すれば大丈夫です。

pm2 logs test-pm2 --lines=100

関連コマンド

ログの削除

しばらくまわしていくと、ログがかなり溜まってきます。不要な場合は以下のコマンドで削除できます。

※指定したアプリのログは全削除になるので、バックアップが必要な場合は取っておきましょう。 ログの保存場所はpm2 show test-pm2で確認できます。

pm2 flush test-pm2
flush-logs

flush後にpm2 logs test-pm2でログを確認すると、空っぽになってます。

logs-after-flush

ログにタイムスタンプをつける

動作確認のログを見れば分かる通り、デフォルトではタイムスタンプがついていません。いつ発生したログなのか分からないのは不便です。

timeオプションでタイムスタンプがつけられます。

# 初回起動の場合
pm2 start test-pm2.py --interpreter=python3 --time

# 再起動の場合
pm2 restart test-pm2 --time

エラーログを見てみると、ちゃんとタイムスタンプがついているのが分かります。これデフォルトにしてほしいですね。

log-with-timestamp

ステータスの確認

アプリの状態はpm2 statusで確認できます。

status

止める場合

pm2 stop アプリ名で止めます。アプリ名は、ステータスで表示されるname列のことです。idnamespaceでの指定もできます。

# pm2 stop `name`
pm2 stop test-pm2
stop

再起動する場合

一度PM2で起動しているアプリなら、pm2 restart アプリ名で再起動できます。同じくnameで指定できます。

pm2 restart test-pm2

ステータスがちゃんとonlineになってますね。

restart

削除する場合

PM2から削除したい場合は以下のコマンドです。

pm2 delete test-pm2

削除すると、pm2 restartで再起動出来なくなります。もう一度pm2 start 実行ファイルから起動する必要があります。

プロセスの記録

サーバなりPCなり、再起動するとPM2が管理していたプロセスは消えてしまいます。 pm2 saveコマンドを打つと、プロセスの情報をディスクに保存してくれます。再起動後、pm2 resurrectで保存したファイルから復元してくれます。ただし、個別のプロセスのステータスはstoppedになっているので手動でrestartする必要があります。この辺の自動起動を設定するコマンドが用意されていますが、私自身まだ試せていないため割愛します。

※ ことあるごとに、コンソールでpm2 saveを打ってください、と言われます。

最後に

PM2の簡単な使い方について書きました。

自動取引BOTが仕事中にエラーで落ちたりしないか、とヒヤヒヤしてきた身としては、まさにゲームチェンジャーです。 もっと早く試していれば良かった、と思えるパッケージです。

他にも

  • 環境変数を設定して起動
  • startup scriptでサーバ再起動後にアプリを自動起動させる
  • configファイルから起動させる

などの機能もあるので、今後も色々試していきたいです。特に1つ目はNODE_ENVを設定して起動したりすることも出来るので、便利そうです。

自動取引ツールやWebサーバアプリなど、常時稼働して欲しいアプリがある場合、ぜひ試してみてください。

記事一覧に戻る