シェルスクリプトデーモンを作成するときにシステムPIDFileの一部であるPIDは何ですか?

シェルスクリプトデーモンを作成するときにシステムPIDFileの一部であるPIDは何ですか?

次のコードに基づいてシェルスクリプトデーモンを作成しました。この回答。次の内容でsystemdサービスファイルを作成しました。

[Unit]
Description=My Daemon
After=network.target

[Service]
Type=forking
PIDFile=/run/daemon.pid
ExecStart=/root/bin/daemon.sh
ExecReload=/bin/kill -1 -- $MAINPID
ExecStop=/bin/kill -- $MAINPID
TimeoutStopSec=5
KillMode=process

[Install]
WantedBy=multi-user.target

echo $$ > /run/daemon.pid;whileループが開始される直前にPIDファイルを生成します(まだそのポイントに達していないため、子プロセスまたは親プロセスではなくデーモンプロセスによって生成されます)。電話をかけると、systemctl status daemon.service次の警告が表示されます。

daemon.service: PID file /run/daemon.pid not readable (yet?) after start: No such file or directory

スクリプトの先頭echo $$ > /run/daemon.pid;(子と親でも使用されます)にPID生成ステートメントを挿入すると、次の警告が表示されます。

daemon.service: PID 30631 read from file /run/daemon.pid does not exist or is a zombie.

systemdから警告メッセージを受け取らずにPIDファイルを生成する最良の方法は何ですか?

答え1

したがって、ここで見られる問題は、Type=forkingpidファイルを使用するときに親プロセスが終了する前に(正しいpidを使用して)pidファイルを生成する必要があるためです。

子プロセスでpidfileを生成すると、親プロセスの終了と競合し、一部(多くの場合)が最初のエラーになります。

子プロセスを開始する前にその子プロセスに書き込むpidファイルを作成すると、終了した親プロセス$$のpidが含まれるため、別のエラーが表示されます。

これを正しく実行する1つの方法は、終了する前に親ファイルのpidfileに書き込むことです。この場合、書き込み$!(代わりに$$)はバックグラウンドで生成された最後のプロセスのpidを返します。

たとえば、

#!/bin/bash

# Run the following code in background:
(
    while keep_running; do
        do_something
    done
) &

# Write pid of the child to the pidfile:
echo "$!" >/run/daemon.pid
exit

これはうまくいきます...しかし、、これを達成するためのより良い方法があります!読んでください...


実際、systemdのポイントは、プロセスをデーモン化してバックグラウンドで実行することです。これを直接実行しようとすると、systemdがそのタスクを実行するのを妨げるだけです。これはまたあなたの人生をさらに困難にします...

を使用する必要はありませんType=forking。実行するシェルスクリプトを作成するだけです。前景に使用するサービスを設定しますType=simple。これでpidファイルは必要ありません。

/root/bin/daemon.sh簡単に次のように更新してください。

#!/bin/bash

# Run the following code in foreground:
while keep_running; do
    do_something
done

(注:daemon.shおそらくこの時点で最高の名前ではありません。バックグラウンドで実行されるという意味です。

.service次に、使用するファイルを更新しますType=simple。 (実際にはここでは基本として使用されるので省略しても構いません。)

[Service]
Type=simple
ExecStart=/root/bin/daemon.sh
ExecReload=/bin/kill -1 -- $MAINPID
ExecStop=/bin/kill -- $MAINPID
TimeoutStopSec=5
KillMode=process

ExecStop=ところで、信号でプロセスを殺すのも基本的な動作なので、おそらくそれを取り除くことができるでしょう...

systemdはType=forking実際にはこのように動作する従来のプログラムでのみ動作し、フォアグラウンドで動作するように簡単に変更することはできません...ひどくて非効率的です。 systemd(およびその代替品、以前のバージョンの一部)の全体的なポイントは、自分自身をフォークしてデーモン化し、サービスが必要な作業にのみ関心を持たせることです! :-)

これが役に立つことを願っています...そしてsystemdがあなたのために重い荷物を負うことを心から願っています!これははるかに効率的です。

答え2

daemon.service: PID file /run/daemon.pid not readable (yet?) after start: No such file or directoryいいですね。サービスファイルに次の文を追加した後、エラーメッセージが消えました。

ExecStartPost=/bin/sleep 2

関連情報