次の構成でUbuntuで実行されているサービスがあります。
#/etc/init/my_service.conf
start on (local-filesystems and net-device-up IFACE=eth1)
respawn
exec python -u /opt/XYZ/my_prog.py 2>&1 \
| logger -t my_prog.py
Sudo service my_service stop
でサービスを停止しても、pythonプロセスは強制終了されません。kill
で親プロセスを強制終了しても、pythonプロセス。
サービスを完全に停止するにはどうすればよいですか(つまり、すべての子プロセスが強制終了されます)?理想的には、上記の構成ファイルを変更したくありません。
理想的には、上記の構成ファイルを変更したくありません。
タフ!それは正しいことです。
exec
をscript
に変更し、パイプラインの一部としてフォークされたサブプロセスでそのpythonプログラムの実行を停止する必要があります。 このServerFault answer 埋め込みシェルスクリプトでこれを行う方法を説明します。最後の行にあるスクリプトに1つだけ変更を加えます。
exec python -u /opt/XYZ/my_prog.py 2>&1
結局のところ、標準エラーもログに記録しない理由はありません。
フォークに対処するためのこれまで以上に複雑な旋回、expect daemon
をsystemd
に切り替えるには、デーモンがフォークするのを停止することが正しいことであるという点を見逃します。現在のカーファッフルから得られる良い点が1つあるとすれば、それは、IBMが1995年に作成し、推奨したものがここ数年正しいことを継続的に確認することです。
チェーンロードデーモンのアイデアに慣れてください。そのようなことを簡単にするツールセットはたくさんあります。シェルスクリプトを使用しないという考えにも慣れてください。この作業のために特別に設計されたツールセットがたくさんあり、シェルのオーバーヘッドを排除します( buntuの世界では良いアイデアとして知られています )。
例:ServerFault回答のShellコマンドは、サブシェルやリンクされていないFIFOなしでこれを実行できるように設計された LaurentBercotのexecline
tools を使用するスクリプトに置き換えることができます。 :
#!/command/execlineb -PW
pipeline -w {
logger -t my_prog.py
}
fdmove -c 2 1
python -u /opt/XYZ/my_prog.py
あなたはそれから単に
exec /foo/this_execlineb_script
my nosh
toolset の場合、同様に以下を含むスクリプトになります。
#!/usr/local/bin/nosh
pipe
fdmove -c 2 1
python -u /opt/XYZ/my_prog.py | logger -t my_prog.py
または、このスタンザをUpstartジョブ定義に直接含めることもできます(Upstartがシェルを生成しないようにシェルメタ文字を回避するトリックを使用)。
exec /usr/local/bin/exec pipe --separator SPLIT fdmove -c 2 1 python -u /opt/XYZ/my_prog.py SPLIT logger -t my_prog.py
GNU/Linuxでは、通常、子プロセスはPPID(親プロセスID)を変更できるため、サービスとそれが生成したすべての子プロセスを停止する方法はありません。知る唯一の方法は、システムコールが作成されたときにプロセスを生成するためにtraceし、これらのプロセスのリストを保持することです。
Ubuntuの初期化システムupstart
は、これを行いません。だからあなたの質問への答えはそれは不可能です-Ubuntuでは-なしで:
これが、 systemd を実行するLinuxディストリビューションを実行する必要がある理由です。ご覧のとおり、systemd すべての子プロセスを追跡します そして1つのコマンドでそれらすべてを強制終了できます。これがGNU/Linuxシステム管理のあり方ですが、systemdは非常に新しく、「ここでは発明されていない」(つまり、Canonicalは発明しなかった)ため、Ubuntu使いたくない。
expectスタンザをスキップしました。 pstart Cookbook は以下を指定します:
警告
このスタンザは非常に重要です:このセクションを注意深く読んでください!
Upstartは、ジョブに属していると思われるプロセスIDを追跡します。ジョブがインスタンススタンザを指定している場合、Upstartはそのジョブの一意のインスタンスごとにPIDを追跡します。
期待スタンザを指定しない場合、Upstartはexecスタンザまたはスクリプトスタンザで実行される最初のPIDのライフサイクルを追跡します。ただし、ほとんどのUnixサービスは「デーモン化」します。つまり、最初のプロセスの子である新しいプロセス(fork(2)を使用)を作成します。多くの場合、サービスは「ダブルフォーク」して、初期プロセスとの関連がまったくないことを確認します。 (そうすることによる追加の利点がないため、最初に2回を超えてフォークするサービスはないことに注意してください)。
この場合、Upstartにはそれを追跡する方法が必要なので、expect forkを使用するか、Upstartがptrace(2)を使用して「フォークをカウント」できるようにするexpectデーモンを使用できます。
Upstartがジョブの最終プロセスIDを決定できるようにするには、そのプロセスがfork(2)を呼び出す回数を知る必要があります。 Upstart自体は、デーモンが実行されると、それ自体が何度でもフォークできる多数の「ワーカー」プロセスをフォークする可能性があるため、この質問に対する答えを知ることができません。この場合、Upstartは、ワーカープロセスが何回作成されるか、またはプロセスが最初にフォークする回数は言うまでもなく、どのPIDが「マスター」であるかを知ることは期待できません。そのため、どのPIDが「マスター」または親PIDであるかをUpstartに通知する必要があります。これは、expectスタンザを使用して実現されます。
パイプがあるのでこれが必要です | 使用しているのは、子プロセスを作成することです。あなたは本の中で見つけることができます 高度なLinuxプログラミング それへの簡単な紹介、それは次のように述べられています:
たとえば、このShellコマンドを使用すると、シェルは2つの子プロセスを生成します。1つはls用、もう1つはless用です。
$ ls | less
私が知らないのは、これが1つまたは2つのフォークを意味するかどうかです。そのため、コードのrespawnの行を次のいずれかで変更してみます。
expect fork
respawn
または
expect daemon
respawn
私のロゴは私がsystemdのファンであることを明確に示していますが、これが達成できるとは思いませんonly with systemd。