TL; DR
daemontools の multilog を落としていない && /service/$service_name/log ディレクトリの i-node が変わると起きる
再現を試みる
デーモンのプロセスだけ落として multilog のプロセスを落としていない疑惑があったので以下のようにして再現を試みた。
service_name=てきとうな名前
if [ -s /service/$service_name ]; then
mv /service/$service_name /service/.$service_name
svc -dx /service/.$service_name
rm -f /service/.$service_name
fi
シンボリックリンクを貼って再起動させる
ln -s ~/$app_name/service /service/$service_name
これで再現できると思ったのだが、multilog が継続して利用され、defunct なプロセスが生成されなかった。
再現を試みる(2)
どうやらシンボリックリンク対象のディレクトリを新規に作れば(別の i-node にすれば)発生するようだ。
service_name=てきとうな名前
if [ -s /service/$service_name ]; then
mv /service/$service_name /service/.$service_name
svc -dx /service/.$service_name
rm -f /service/.$service_name
fi
cp -a ~/$app_name/service /tmp/service
sudo rm -rf /tmp/service/supervise
sudo rm -rf /tmp/service/log/supervise
rm && cp でディレクトリを作り直す(疑似デプロイ)
rm -rf ~/$app_name/service
cp -a /tmp/service ~/$app_name/service
シンボリックリンクを貼る
ln -s ~/$app_name/service /service/$service_name
これで新しく生えた multilog が defunct になった。
[supervise] <defunct>
ps でみると [multilog] <defunct> ではなく [supervise] <defunct> になっている。 なぜ supervise の下に supervise がぶら下がっているのか気になって調べた。
$ ps auxwwf
root 4448 0.0 0.0 3984 368 ? S 2013 88:09 | \_ supervise $service_name
root 30562 0.0 0.0 0 0 ? Z 22:18 0:00 | | \_ [supervise] <defunct>
結論からいうと、fork してから execve する前に死んでいたのでプロセスの名前が [supervise] のままになっていたのであろう。
$ sudo strace -f -p 4448
[pid 14161] <... rt_sigprocmask resumed> NULL, 8) = 0
[pid 14161] execve("./run", ["./run"], [/* 1 var */]) = -1 ENOENT (No such file or directory)
[pid 14161] write(2, "supervise: fatal: unable to star"..., 70) = 70
ちなみに該当ディレクトリのパスには run ファイルがある。にも関わらず No such file or directory と言われている。
これは、$ sudo ls -l /proc/4448/cwd
するとシンボリック先が (deleted) となっているのが原因で、 どうやら daemontools はディレクトリのパスではなく i-node を追っているようだ。 追っている i-node のディレクトリが消えたので run ファイルが見えなくなり、No such file or directory といって落ちている。
rm && cp しないと defunct にならない件について
rm && cp しない場合は defunct 現象が発生せず、multilog が正常に動作してしまっていたのが解せなかったので調査した。 デーモンが TERM されていて、multilog だけが生きている状況で、どのように multilog への出力が継続されるのだろうか。
こちらに以下のような記述があった。http://www.unixuser.org/~euske/doc/daemontools/myfaq/faq-1.html
じつは svscan は supervise の終了を検知するようになっており、 既知のディレクトリに対しては何度 supervise を実行しても 同じパイプのファイル記述子を使うようになっている。これによって、 たとえばデーモン用の supervise が再起動しても、log 用の supervise は そのまま継続してこの新しい supervise からログを取ることができる。
svscan がパイプを管理していて、既知のディレクトリ(i-node で識別される)に対しては良きに計らってくれるようだ。しかし、i-node が変わると継続されずに新規に multilog の起動を試みるようになり、しかしすでに起動している multilog があるためすぐに死に、 親プロセスが wait して適切に処理してくれるまでは defunct になり、親に処理されては消え、そしてまた起動を試みられ、死ぬ、を繰り返し続けることになる。
確認してみたところ、確かに svscan が持っているパイプと supervise がもっているパイプが同じだった。
# svscan
$ sudo ls -l /proc/9402/fd
lr-x------ 1 root root 64 8月 6 03:51 0 -> /dev/null
l-wx------ 1 root root 64 8月 6 03:51 1 -> pipe:[1667674317]
l-wx------ 1 root root 64 8月 6 03:51 2 -> pipe:[1667674317]
lr-x------ 1 root root 64 8月 6 03:51 6 -> pipe:[1667703193] *
l-wx------ 1 root root 64 8月 6 03:51 7 -> pipe:[1667703193] *
# supervise daemon
$ sudo ls -l /proc/19999/fd
lr-x------ 1 root root 64 8月 6 03:51 0 -> /dev/null
l-wx------ 1 root root 64 8月 6 03:51 1 -> pipe:[1667703193] *
l-wx------ 1 root root 64 8月 6 03:51 2 -> pipe:[1667674317]
lr-x------ 1 root root 64 8月 6 03:51 3 -> pipe:[1667704094]
l-wx------ 1 root root 64 8月 6 03:51 4 -> pipe:[1667704094]
# supervise log
$ sudo ls -l /proc/20000/fd
lr-x------ 1 root root 64 8月 6 03:54 0 -> pipe:[1667703193] *
l-wx------ 1 root root 64 8月 6 03:54 1 -> pipe:[1667674317]
l-wx------ 1 root root 64 8月 6 03:54 2 -> pipe:[1667674317]
lr-x------ 1 root root 64 8月 6 03:54 3 -> pipe:[1667704095]
l-wx------ 1 root root 64 8月 6 03:54 4 -> pipe:[1667704095]
# daemon
$ sudo ls -l /proc/24839/fd
lr-x------ 1 root root 64 8月 6 03:54 0 -> /dev/null
l-wx------ 1 root root 64 8月 6 03:54 1 -> pipe:[1667703193] *
l-wx------ 1 root root 64 8月 6 03:54 2 -> pipe:[1667703193] *
lr-x------ 1 root root 64 8月 6 03:54 3 -> pipe:[1667725780]
l-wx------ 1 root root 64 8月 6 03:54 4 -> pipe:[1667725780]
lr-x------ 1 root root 64 8月 6 03:54 5 -> /dev/null
l-wx------ 1 root root 64 8月 6 03:54 6 -> /dev/null
# multilog
$ sudo ls -l /proc/20056/fd
lr-x------ 1 game game 64 8月 6 03:56 0 -> pipe:[1667703193] *
l-wx------ 1 game game 64 8月 6 03:56 1 -> pipe:[1667674317]
l-wx------ 1 game game 64 8月 6 03:56 2 -> pipe:[1667674317]