簡易なバックグラウンドプロセス管理ツールを実装してみた
はじめに
ども、最近Claude Codeにすべてをかけているゴリラです。
Claude Codeくんを使って開発していく中で、ときたまバックグラウンドでプロセスを実行したいときがあります。
例えばnpm run dev
で開発サーバーを起動して、playwright mcpで画面の確認をしようとすると、
Claude Codeくんは普通にnpm run dev &
を実行しようとします。
しかしそれだとバックグラウンドで実行できないので、簡易な管理ツールをCaude Codeくんに作ってもらいました。
README.mdをClaude Codeくんに食わせてバックグラウンドでプロセスを動かしたいときはこれを使ってねって依頼するとこうふうにいい感じにやってくれます。
作ったもの
見えないところでプロセスが動くということで ghost(幽霊) という名前にしてみました。
主な機能としては以下のようになっています。
- プロセスの起動・停止
- プロセスの状態確認
- プロセスの標準・エラー出力の確認
- TUI画面
使い方はこんな感じです。
# sleep 10 をバックグラウンドで実行
$ ghost run sleep 10
# タスク一覧
$ ghost list
# タスク停止
$ ghost stop {taskid}
# TUI起動
$ ghost
アーキテクチャ
同じようなツールとして以下のものがありますが、どちらもdaemonを常駐してプロセスを管理させる設計になっています。
ghostはdaemonを使わず、シンプルにsqliteにプロセスの管理情報を持たせて、コマンド実行時にプロセスの実行状態と同期させています。
プロセスの厳密の管理ができないというデメリットがありますが、今回の用途ではこれで充分です。
プロセスの出力に関してはファイルに書き出すようにしていて、必要なときに中身を参照できるようにしています。
┌────────────┐ ┌────────────┐
│ ghost CLI │ ──── spawn ──────▶ │ background │
│ (clap) │ │ process │
└────────────┘ └────────────┘
│ │
│ write write │
▼ ▼
┌────────────┐ ┌────────────┐
│ SQLite DB │ │ Log Files │
│ (tasks.db) │ │ (*.log) │
├────────────┤ └────────────┘
│ Task table │ │
│ PID info │ read │
│ Status │ ▼
└────────────┘ ┌────────────┐
▲ │ ghost │
│ read/update │ TUI │
└────────────────────────────│ (ratatui) │
└────────────┘
またpueueとtask-spoolerと大きな違いとしてghostはTUI画面を用意しています。
やはり時代はTUIですね。
プロセス管理
受け取ったコマンドをバックグラウンドで実行する処理はこの部分ですが、ポイントはsetsid(2)
を実行している部分です。
setsid(2)
を理解するにはまずセッションとプロセスグループについて理解する必要があります。
プロセスグループは関連するプロセスの集合でシグナルを一括で送信できる単位として機能します。
セッションは、1つ以上のプロセスグループの集合です。
setsid(2)
を使うと、子プロセスが新しいセッションとプロセスグループのリーダーになり、実行しているghostとターミナルから分離されます。
プロセスグループリーダーなると、孫以降がそのプロセスグループにまとめられるので、プロセスグループをkillすると孫以降のプロセスをまとめてkillできます。
実行前の状態:
┌─────────────────────────────────┐
│ Terminal Session (SID=1000) │
│ ┌─────────────────────────────┐ │
│ │ Shell (PID=1000, PGID=1000) │ │
│ │ └─ ghost (PID=2000) │ │
│ └─────────────────────────────┘ │
│ terminal: /dev/pts/0 │
└─────────────────────────────────┘
setsid()実行後:
┌─────────────────────────────────┐ ┌────────────────────────────┐
│ Terminal Session (SID=1000) │ │ New Session (SID=2001) │
│ ┌─────────────────────────────┐ │ │ ┌────────────────────────┐ │
│ │ Shell (PID=1000, PGID=1000) │ │ │ │ Task (PID=2001) │ │
│ └─────────────────────────────┘ │ │ │ PGID=2001 │ │
│ terminal: /dev/pts/0 │ │ └────────────────────────┘ │
└─────────────────────────────────┘ │ terminal: nothing │
└────────────────────────────┘
シーケンス図にするとこんな感じです。
Vibe Codingについて
がっつりAIに実装してもらったものはこれが初めてだけど、そこまで詰まることなく開発できたかなという印象です。
アーキテクチャの壁打ちから一緒にやりましたが、自分の知らないことも多々あり勉強になることも多かったです。
実装はAIを使ったほうが速かったんですが、TUIの部分に関してはUIの調整が難しかったです。例えばborderの位置がズレていたりします。
画像を貼って指示してもなかなか想定通りのUIにできなかったので、そういった部分は手修正しました。
こういう小さなツールを作るとき、もうClaude Codeなしでは作れない体になってしまったのかもしれないです。ぴえん
さいごに
プロセス管理についてあんまりよくわかっていなかったので、今回の実装でちょっと理解できたのはよかったです。
また、RustではTUIを作ったのも初めてだけど、ratatuiは割と直感的な設計になっていてコードがわかりやすかったです。
Discussion