at backyard

Color my life with the chaos of trouble.

Rustのプロセスをデーモン化するためのdaemonizeを試してみた

最初に

個人的な備忘録。 また私はプロセスのデーモン化などはあまり経験がないため、誤ったことを書いている可能性もある。その点ご承知おきください。
(誤っている点などあればコメントいただけると幸いです)

Rustで作成したプロセスをデーモン化する

これはRustで作成したプログラムをデーモン化させる方法について調べたメモ。

手っ取り早くデーモン化させるなら daemonize が便利そうだったので、こちらを今回試してみた。

https://crates.io/crates/daemonize

daemonizeを用いたサンプル

下記のようなシンプルなコードを用意する。
実行すると一定間隔で自身のプロセスIDを出力するだけのプログラム。

use std::{thread, time};
use std::process;

fn run() {
    let ten_millis = time::Duration::from_millis(1000);
    loop {
        println!("pid: {}", process::id());
        thread::sleep(ten_millis);
    }
}

fn main() {
    run();
}

このプログラムをデーモン化させる。
ソースコードdaemonize 内のドキュメントに記載されているものを参考にしているが、一部記述を変更したり省いたりもしている。

deamonizeを用いて下記のようにすることでバックグラウンドプロセスとして起動してくれるようになる。
出力は ./daemon-dir/daemon.out 内に出力される。

extern crate daemonize;

use std::fs::File;
use std::{thread, time};
use std::process;

use daemonize::Daemonize;

fn run() {
    let ten_millis = time::Duration::from_millis(1000);
    loop {
        println!("pid: {}", process::id());
        thread::sleep(ten_millis);
    }
}

fn main() {
    let stdout = File::create("./daemon-dir/daemon.out").unwrap();
    let stderr = File::create("./daemon-dir/daemon.err").unwrap();

    let daemonize = Daemonize::new()
        .pid_file("./daemon-dir/test.pid")
        .working_directory("./daemon-dir")
        .stdout(stdout)
        .stderr(stderr)
        .exit_action(|| println!("Executed before master process exits"))
        .privileged_action(|| return "Executed before drop privileges");

    match daemonize.start() {
        Ok(v) => {
            println!("{:?}", v);
            println!("Success, daemonized");
            run();
        },
        Err(e) => eprintln!("Error, {}", e)
    }
}

実際に cargo run を実行すると、 Executed before master process exits という文字列が表示されて、あとは処理が切り離される。
以降は ./daemon-dir/daemon.out にひたすら出力が行われていく形となる。
プロセスを止める場合は kill {プロセスID} を実行してプロセスを止めた。

上のコードをいくつか補足しておくと、

  • exit_action は親プロセスが終了する直前に実行される。そのためここに記載したprintln! はターミナル上に表示されている。一般的なユースケースとしてはフォークされたプロセスと同期することが挙げられる、とdaemonize内のソースコードには記載がある
  • privileged_action での処理は特権が放棄される直前(というのは親プロセスからforkされる直前と同じ意味だろうか。ちょっと理解できていない)に実行される。このactionの実行結果はstartメソッドで返されるため、上のコードの場合、 Ok(v) => {vの中に文字列が入っている形となる。よって、 daemon.out の出力は以下のようになる。この箇所に関する一般的な使用例としては、リスニング用のソケットをオープンすることなどが挙げられるようだ。

daemon.out の出力

"Executed before drop privileges"
Success, daemonized
pid: {プロセスID}
pid: {プロセスID}
pid: {プロセスID}
pid: {プロセスID}
pid: {プロセスID}

daemonizeを用いたプロセスのデーモン化についてのメモは以上となる。