Jupyter LabをローカルのMacで使っており、それを起動するバッチを自作して使っているのですが、たまにすでに起動してるのにそのバッチを実行してしまってJupyterのプロセスを2重に立ち上げてしまうことが度々ありました。
2個立ち上げっぱなしとなると気持ち悪いのでPIDを調べてkillする必要がありやらかすとちょっと面倒なミスです。
最初、この対策としてプロセスをgrepしてjupyterがすでに立ち上がってたらバッチを中断して起動コマンドを叩かない、みないな処理を入れて対応しようとも試みていたのですが、grep jupyter 自身がそのgrepにヒットするというなかなか困った挙動をしうまくいかずに放置していました。
しかしその後、プロセス一覧ではなくポートが使用中かどうかで判断すれば良いと思いついたので実装してみました。
利用するのは、lsof というコマンドです。これはポートに限らず、システムで開いているファイルの一覧を表示するコマンドです。名前も List Open Files の略だそうです。
今回はポートの情報だけ知れたらいいので、 -i 引数をつけます。そして、さらにコロンを打ってポート番号を指定すると、そのポートが使用されていれば使用しているプロセスの一覧が各種情報とともにずらずらと表示されます。
Jupyter Labは デフォルトでは 8888番ポートで動作するので、次のようなコマンドで確認できます。
$ lsof -i :8888
# 8888番ポートが使われていなければ何も表示されない。
# Jupyter Labが起動していると各プロセスが結果に出る。
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
Google 808 yutaro 21u IPv6 0x12572c541560807 0t0 TCP localhost:49319->localhost:ddi-tcp-1 (ESTABLISHED)
Google 808 yutaro 34u IPv4 0x12572d3a3516cff 0t0 TCP localhost:49234->localhost:ddi-tcp-1 (ESTABLISHED)
Google 808 yutaro 37u IPv6 0x12572c541540007 0t0 TCP localhost:49253->localhost:ddi-tcp-1 (ESTABLISHED)
Google 808 yutaro 80u IPv6 0x12572c54155b807 0t0 TCP localhost:49213->localhost:ddi-tcp-1 (ESTABLISHED)
Google 808 yutaro 108u IPv6 0x12572c541546007 0t0 TCP localhost:49216->localhost:ddi-tcp-1 (ESTABLISHED)
python3.1 1096 yutaro 11u IPv4 0x12572d3a351ba6f 0t0 TCP localhost:ddi-tcp-1 (LISTEN)
python3.1 1096 yutaro 12u IPv6 0x12572c54154a007 0t0 TCP localhost:ddi-tcp-1 (LISTEN)
python3.1 1096 yutaro 13u IPv6 0x12572c54155e807 0t0 TCP localhost:ddi-tcp-1->localhost:49319 (ESTABLISHED)
python3.1 1096 yutaro 14u IPv6 0x12572c54155c007 0t0 TCP localhost:ddi-tcp-1->localhost:49213 (ESTABLISHED)
python3.1 1096 yutaro 16u IPv6 0x12572c541548007 0t0 TCP localhost:ddi-tcp-1->localhost:49216 (ESTABLISHED)
python3.1 1096 yutaro 37u IPv4 0x12572d3a351780f 0t0 TCP localhost:ddi-tcp-1->localhost:49234 (ESTABLISHED)
python3.1 1096 yutaro 50u IPv6 0x12572c54153e807 0t0 TCP localhost:ddi-tcp-1->localhost:49253 (ESTABLISHED)
Python は3.11を使っているのに、COMMAND名が途中で切り捨てられて3.1って表示されていますが、まぁ、Pythonで何か動いているのはわかりますね。
あとは、Jupyter Labの起動バッチで、このコマンドを動かして処理を分岐させればOKです。
(自分はnohupコマンドの結果を専用のログファイルにログを書き出しているのですが、不要なら/dev/null あたりに捨てても良いと思います。)
if 文の条件文の中で出力を /dev/nullに捨てているのは出力をすっきりさせるためです。捨てない場合は普通に画面にlsofコマンドの結果も表示されます。
#!/usr/bin/env zsh
if lsof -i:8888 > /dev/null; then
echo "8888番ポートは既に使用されています。"
exit 1
else
cd ~
nohup jupyter lab >> ~/Documents/log/jupyter_lab.log 2>&1 &!
cd -
fi
cd ~ はホームディレクトリに移動する、 cd – は元のディレクトリに戻る、です。
どこで打ってもホームディレクトリでJupyter Labが起動されるように、そしてそのあとは元のディレクトリに帰るようにしています。
この記事を書いた後に気づいきましたが、このlsofコマンドは以前こちらの記事でも使っていましたね。
参考: sshtunnel を使って踏み台サーバー経由でDB接続