時間がかかる複数のCLIタスクをRust製ツールのPueueで管理する
rsyncによる大容量ファイルの転送やDBのバックアップ・リストアなど、たびたび非常に時間がかかるタスクをCLIで実行するシーンがあります。
通常そういった場合は末尾に&
を付加(セッションが切れても中断されないようにnohup
とセットで使うことも多い)してバックグラウンドで動作させるのが一般的かと思います。
ただ、そのまま使うとログや実行時間、リターンコードなどの採取が面倒であり、いささか一覧性に欠けます。
そんな中、そのようなユースケースに適したPueueという管理ツールが登場しました。
Pueueとは
Pueueとは、長時間のCLIタスクに特化したOSSの管理ツールです。
最近はstarship
やnushell
といったRust製のツールが勢いを増していますが、例によってPueueもRustによって記述されています。
Pueueの特徴としては、次の通りです。
- リッチなUI: バックグラウンドで実行したコマンドの返り値、実行したパス、開始・終了時間などを一覧で閲覧可能
- タスクの実行制御: 個々のバックグラウンドタスクを直列・並列で動作させるオプションや、その並列数などを指定可
- タスクのグループ化: 複数のタスクを特定のグループに所属させることで、まとめて開始・停止可
同種のタスクをキュー化するツールとしてはnqやtask-spoolerなどが挙げられますが、多くのパッケージマネージャーに対応し、
手動で入れる場合もバイナリを2つ配置するだけで利用を開始できる点でPueueの方が導入の敷居は低いかと思われます。
それでは、ハンズオンしながら動きを見ていきましょう。
環境
- OS: MacOS Catalina 10.15.7[1]
- Pueue: v0.11.1
ハンズオン
事前準備
- インストール
ビルド済みのバイナリをPATHが通ったところに配置します。
次のように、クライアントであるpueue
とデーモンであるpueued
のインストールを行います。
$ curl -sL -o pueue https://github.com/Nukesor/pueue/releases/download/pueue-v0.11.1/pueue-macos-x86_64
$ curl -sL -o pueued https://github.com/Nukesor/pueue/releases/download/pueue-v0.11.1/pueued-macos-x86_64
$ mv pueue* /usr/local/bin
$ chmod +x /usr/local/bin/pueue*
今回は便宜上直接バイナリを配置する形でインストールを行いましたが、本来はパッケージマネージャーからのインストールが推奨されているため、
そちらから導入する場合は公式のREADMEを参考にしてください。
- バージョン確認
インストール後、それぞれ正常に返ってくればOKです。
$ pueue -V
Pueue client 0.11.1
$ pueued -V
Pueue daemon 0.11.1
- pueuedをバックグラウンドで実行
Pueueを利用するためには、事前にデーモンとしてpueuedを起動しておく必要があるので、
バックグラウンドで立ち上げておきます。
$ pueued -d
Pueued is now running in the background
なお、-d
オプションを省略するとフォアグラウンドで実行することも可能です。
もしSystemdを利用していて、かつパッケージマネージャーを使用せずにインストールした場合は、公式Wikiを参考にしてSystemdのUnitを作成・有効化してください。
手順
- タスクを追加
ここまででPueueを利用する準備が整いましたので、pueue add -- <command>
でタスクを追加します。
今回は、単にls
コマンドを実行します。
$ pueue add -- ls
New task added (id 0).
タスクを追加すると、上記のようにタスクにIDが振られます。
- ステータス確認
pueue status
によってタスクの状況を確認します。
$ pueue status
Group "default" (1 parallel): running
─────────────────────────────────────────────────────────────────────────────────
Index Status Exitcode Command Path Start End
═════════════════════════════════════════════════════════════════════════════════
0 Success 0 ls /Users/ryoichi/work/tips 12:03 12:03
─────────────────────────────────────────────────────────────────────────────────
このように、追加したタスクの返り値、実行したパス、開始・終了時間を一覧で確認できます。
- ログの確認
追加したタスクのIDが0
であることが確認できたので、ログを確認します。
ログの確認は、pueue log <task_id>
で行います。
$ pueue log 0
Task 0 completed successfully
──────────────────────────────────────────
Command: ls
Path: /Users/ryoichi/work/tips
Start: Sun, 14 Feb 2021 12:03:05 +0900
End: Sun, 14 Feb 2021 12:03:05 +0900
stdout:
README.md
articles
books
node_modules
package.json
yarn.lock
pueue status
で閲覧できた内容に加えて、出力結果も確認できました。
- お掃除する
実行が完了したタスクをクリーンアップしたいときは、pueue clean
[2]を使います。
$ pueue clean
All finished tasks have been removed
$ pueue status
Task list is empty. Add tasks with `pueue add -- [cmd]`
- 時間がかかるタスクを追加
ls
コマンドは瞬時に完了してしまうので、時間がかかるタスクを2つ追加します。
# タスクを追加
$ pueue add -- 'for i in `seq 1 1000`; do echo $i; sleep 5; done'
New task added (id 0).
$ pueue add -- 'for i in `seq 1 1000`; do echo $i; sleep 5; done'
New task added (id 1).
# タスク一覧
$ pueue status
Group "default" (1 parallel): running
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Index Status Exitcode Command Path Start End
════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
0 Running for i in `seq 1 1000`; do echo $i; sleep 5; done /Users/ryoichi/work/tips 15:50
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
1 Queued for i in `seq 1 1000`; do echo $i; sleep 5; done /Users/ryoichi/work/tips
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
デフォルトでは並列数は1なので、2つ目のタスクはQueued
となり、待ち状態となります。
- 並列数を上げる
Pueueではタスクを並列で実行することもできるので、次のように変更します。
$ pueue parallel -g default 2
Parallel tasks setting for group "default" adjusted
グループ設定を行わない場合、タスクはdefault
というグループに属するため、このグループに対して並列数を2に指定しています。
もう一度pueue status
すると、2 parallel
となって2つ目のタスクもRunning
ステータスに移行したことが確認できます。
$ pueue status
Group "default" (2 parallel): running
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Index Status Exitcode Command Path Start End
════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
0 Running for i in `seq 1 1000`; do echo $i; sleep 5; done /Users/ryoichi/work/tips 15:50
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
1 Running for i in `seq 1 1000`; do echo $i; sleep 5; done /Users/ryoichi/work/tips 16:02
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
- 複数タスクのログを確認
Pueueでは、そのサブコマンドの多くは複数のタスクに対して同時に実行できます。
例えば、ログを確認するpueue log <task_id>
はpueue log <task_id1> <task_id2>
とまとめて実行することができます。
$ pueue log 0 1
Task 0 running
───────────────────────────────────────────────────────────
Command: for i in `seq 1 1000`; do echo $i; sleep 5; done
Path: /Users/ryoichi/work/tips
Start: Sun, 14 Feb 2021 15:50:54 +0900
stdout:
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
Task 1 running
───────────────────────────────────────────────────────────
Command: for i in `seq 1 1000`; do echo $i; sleep 5; done
Path: /Users/ryoichi/work/tips
Start: Sun, 14 Feb 2021 16:02:07 +0900
stdout:
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
ちなみにデフォルトではログの出力結果が省略されますが、もし全てのログを確認したい場合は-f(--full)
オプションを付与することでログの全文を取得できます。
- リアルタイムでログを見る
Pueueでは、pueue follow
でtail -f
相当の処理を行うこともできます。
$ pueue follow 0
(省略)
481
482
483
484
485
- 実行中のタスクを停止
もし実行したタスクを途中で停止したくなった場合は、pueue pause
で一時停止するか、
あるいはpueue remove
で完全にタスクを削除することができます。
今回は、前者の一時停止を行います。
$ pueue pause 1
Tasks are being paused: 1
次に、ステータスを確認します。
$ pueue status
Group "default" (2 parallel): running
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Index Status Exitcode Command Path Start End
════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
0 Running for i in `seq 1 1000`; do echo $i; sleep 5; done /Users/ryoichi/work/tips 15:50
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
1 Paused for i in `seq 1 1000`; do echo $i; sleep 5; done /Users/ryoichi/work/tips 16:02
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Running
からPaused
にステータスが変わりました。
それでは、pueue follow
で出力の動きを確認してみましょう。
$ pueue follow 1
(省略)
447
448
449 ←ここで止まる
すると、処理が止まっていることが確認できます。
次に、pueue start
でPausedしているタスクを再開してみましょう。
$ pueue start 1
Tasks are being started: 1
$ pueue status
Group "default" (2 parallel): running
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Index Status Exitcode Command Path Start End
════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════
0 Running for i in `seq 1 1000`; do echo $i; sleep 5; done /Users/ryoichi/work/tips 15:50
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
1 Running for i in `seq 1 1000`; do echo $i; sleep 5; done /Users/ryoichi/work/tips 16:02
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Paused
からRunning
に戻りました。
再びログを確認します。
$ pueue follow 1
(省略)
461
462
463
このように、順調に後続の処理を再開していることが確認できます。
- 再びお掃除する
先ほど実行が完了したタスクのクリーンアップに使えるpueue clean
を紹介しましたが、
実行中のタスクも含めてクリーンアップしたい場合はpueue reset
を利用できます。
# 実行中のタスクがある場合は、Y/nのプロンプトが出る
$ pueue reset
You are trying to remove running tasks: task0, task1
Do you want to continue [Y/n]: Y
Everything is being reset right now.
$ pueue status
Task list is empty. Add tasks with `pueue add -- [cmd]`
- デーモンを停止する
最後に、デーモンを停止する方法を紹介します。
Systemdの管理下にないpueuedを停止したい場合は、pueue shutdown
で停止できます。
$ pueue shutdown
Daemon is shutting down
$ pueue status
Error: Couldn't find unix socket at path "/Users/ryoichi/.local/share/pueue/pueue_ryoichi.socket". Is the daemon running yet?
最後に
インストール先の依存がほとんどなく、必要そうな機能は網羅されていることから、使い心地は非常に良かったです。
ただ、デーモンの管理が必要であったり、たびたび破壊的変更が行われていてまだ安定しているステータスでなかったりと、
現時点では本番環境というよりは開発用のワークスペース向きという感触です。
今回は紹介しませんでしたが、他にもタスクの依存関係を設定する機能やプロセスに対して確認の'y\n'を送信する機能、リモートのpueuedに接続してタスクを追加する機能[3]などがあるため、
また気が向いたら別の記事で紹介したいと思います。
Discussion