【Rust】プロセスの監視と再起動
#Rust #tips #プロセス #wip
すごく単純なプロセスの再起動コード
code: rust
use std::process::Command;
use std::thread;
use std::time::Duration;
fn main() {
thread::spawn(|| {
loop {
println!("子プロセスを起動します...");
let mut child = Command::new("sleep")
.arg("100")
.spawn()
.expect("プロセスの起動に失敗しました");
let _ = child.wait();
thread::sleep(Duration::from_secs(1));
}
});
loop {
println!("親プロセスは作業中...");
thread::sleep(Duration::from_secs(5));
}
}
ポイント
メインスレッドから子プロセスの起動を独立させる。
さらに、スレッドのloop内で起動させ、そしてそのプロセスをwaitで待つ。
waitに捕まったらプロセスが終了したということ。
loopが再度回ることで同じコマンドが再実行される。
他方、メインスレッドの方は独立してずっと動ける。
別にloopにせずとも、thread::spawnからhandleをもらって、handle.join()で待ってもいい。
supervisorなどの仕組みを使わずとも、めっちゃシンプルでいいならこういうのもあり。
ただし...注意書きはある。
上記の懸念
終了理由で再起動するか否か決めたい場合はどうするか
threadが落ちたら子プロセスも落ちるようにできるか(ゾンビ化対策)
プロセスが死なずにハングした場合の対応はできるか
プロセスがすぐ死んでしまい、loopが何度も起きてしまう場合の対応は?
プロセスとのやり取りとかあったらどうする?
プロセスのエラーはどうやってログ記録する?
など
上記はシンプルすぎるので、懸念に対応したものを構築する必要はあるだろう。
保守性部分は特に気をつけるべき。
並行処理するならtokioを使うと良いかもしれない。
オーバースペックの可能性もあるので選択するかは注意。
いずれにせよtokioに慣れてないと判断できないがな。練習あるのみ。
code:rust
use std::process::Stdio;
use std::time::Duration;
use tokio::process::Command;
use tokio::time;
#tokio::main
async fn main() {
// 子プロセス監視のタスクを生成
tokio::spawn(async {
loop {
println!("子プロセスを起動します...");
// 非同期にプロセスを起動
let mut child = Command::new("sleep")
.arg("100")
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.expect("プロセスの起動に失敗しました");
// 非同期に子プロセスの終了を待つ
let status = child
.wait()
.await
.expect("子プロセス待機中にエラーが発生しました");
println!(
"子プロセスが終了しました。終了ステータス: {:?}",
status.code()
);
// 再起動前に少し待機
time::sleep(Duration::from_secs(1)).await;
}
});
// メインタスクはこちらで継続
loop {
println!("親プロセスは作業中...");
time::sleep(Duration::from_secs(5)).await;
}
}