systemd
は、管理対象プロセスの子の死をどのように処理しますか?
systemd
がデーモンfoo
を起動し、それが次にbar1
、bar2
、およびbar3
の3つのデーモンを起動するとします。 bar2
が予期せず終了した場合、systemd
はfoo
に対して何かしますか?私の理解では、Solarisのサービス管理機能(SMF)の下で、foo
に通知しないと、プロパティignore_error
を変更することにより、startd
が強制終了または再起動されます。 systemd
の動作は異なりますか?
編集#1:
systemd
の動作をテストするテストデーモンを作成しました。デーモンは子を生成するため、mother_daemon
と呼ばれます。
#include <iostream>
#include <unistd.h>
#include <string>
#include <cstring>
using namespace std;
int main(int argc, char* argv[])
{
cout << "Hi! I'm going to fork and make 5 child processes!" << endl;
for (int i = 0; i < 5; i++)
{
pid_t pid = fork();
if (pid > 0)
{
cout << "I'm the parent process, and i = " << i << endl;
}
if (pid == 0)
{
// The following four lines rename the process to make it easier to keep track of with ps
int argv0size = strlen(argv[0]);
string childThreadName = "mother_daemon child thread PID: ";
childThreadName.append( to_string(::getpid()) );
strncpy(argv[0],childThreadName.c_str(),argv0size + 25);
cout << "I'm a child process, and i = " << i << endl;
pause();
// I don't want each child process spawning its own process
break;
}
}
pause();
return 0;
}
これは、mother_daemon.service
というsystemd
ユニットで制御されます。
[Unit]
Description=Testing how systemd handles the death of the children of a managed process
StopWhenUnneeded=true
[Service]
ExecStart=/home/my_user/test_program/mother_daemon
Restart=always
mother_daemon.service
ユニットはmother_daemon.target
によって制御されます:
[Unit]
Description=A target that wants mother_daemon.service
Wants=mother_daemon.service
Sudo systemctl start mother_daemon.target
を実行すると(Sudo systemctl daemon-reload
の後)、親デーモンと5つの子デーモンが表示されます。
子の1つを殺しても親には影響はありませんが、親を殺す(したがって再起動をトリガーする)と子が再起動します。
mother_daemon.target
でSudo systemctl stop mother_daemon.target
を停止すると、子も終了します。
これは私の質問に答えると思います。
メインプロセスは、通常の方法でその子の死を処理します。
これはPOSIXの世界です。プロセスAがBをフォークし、プロセスBがC、D、およびEをフォークした場合。次に、プロセスBは、C、D、およびEの終了からSIGCHLD
およびwait()
ステータスを参照するものです。プロセスAは、C、D、およびEに何が起こるかを認識していません。 systemdに関係ありません。
AがC、D、およびEの終了を認識するには、2つのことが発生する必要があります。
service-manager
_などの他のさまざまなサービスマネージャーと同様にこれを行います。exit()
でなければなりません。 愚かに、誤って、そして無駄に 自分自身を「デーモン化」しようとするサービスはこれを行います。(BSDでkevent()
を使うと賢くなります。しかし、これはLinuxの質問です。)
systemd
には、メインプロセスの概念があります。 systemdのドキュメントでは、これは「メインサービスプロセス」または単に「メインプロセス」と呼ばれています。
systemd.serviceドキュメント の例4は、メインプロセスがType=forking
のときに計算されると説明しています。
systemd.service docsのRestart=
に関するドキュメント メインプロセスに関連してサービスが開始されるときのさまざまな可能性について説明します。
上記の「例4」からのキーテキストは次のとおりです。
systemdは、元のプログラムがまだ実行されている間、サービスが初期化中であると見なします。正常に終了し、少なくともプロセスが残っている場合(およびRemainAfterExit = no)、サービスは開始されていると見なされます。
多くの場合、従来のデーモンは1つのプロセスのみで構成されています。したがって、元のプロセスの終了後にプロセスが1つだけ残っている場合、systemdはそのプロセスをサービスのメインプロセスと見なします。その場合、$ MAINPID変数はExecReload =、ExecStop =などで使用できます。
複数のプロセスが残っている場合、systemdはメインプロセスを判別できないため、メインプロセスがあるとは想定しません。その場合、$ MAINPIDは何にも展開されません。ただし、プロセスが従来のPIDファイルを書き込むことを決定した場合、systemdはそこからメインPIDを読み取ることができます。 PIDFile =を適宜設定してください。