👋

時間がかかる複数のCLIタスクをRust製ツールのPueueで管理する

2021/02/14に公開

rsyncによる大容量ファイルの転送やDBのバックアップ・リストアなど、たびたび非常に時間がかかるタスクをCLIで実行するシーンがあります。
通常そういった場合は末尾に&を付加(セッションが切れても中断されないようにnohupとセットで使うことも多い)してバックグラウンドで動作させるのが一般的かと思います。
ただ、そのまま使うとログや実行時間、リターンコードなどの採取が面倒であり、いささか一覧性に欠けます。
そんな中、そのようなユースケースに適したPueueという管理ツールが登場しました。

Pueueとは

https://github.com/Nukesor/pueue

Pueueとは、長時間のCLIタスクに特化したOSSの管理ツールです。
最近はstarshipnushellといったRust製のツールが勢いを増していますが、例によってPueueもRustによって記述されています。

Pueueの特徴としては、次の通りです。

  • リッチなUI: バックグラウンドで実行したコマンドの返り値、実行したパス、開始・終了時間などを一覧で閲覧可能
  • タスクの実行制御: 個々のバックグラウンドタスクを直列・並列で動作させるオプションや、その並列数などを指定可
  • タスクのグループ化: 複数のタスクを特定のグループに所属させることで、まとめて開始・停止可

同種のタスクをキュー化するツールとしてはnqtask-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 followtail -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]などがあるため、
また気が向いたら別の記事で紹介したいと思います。

脚注
  1. 2021年2月現在の主なサポート対象OSはLinuxであり、MacとWindowsは部分的なサポートとなるようです ↩︎

  2. このタイミングでタスクのログが消えてしまうので、実行する前にログの採取はしておきましょう ↩︎

  3. まだ試していないですが、セキュリティ的にはちょっと…かも ↩︎

Discussion