web-dev-qa-db-ja.com

サービスによって生成されたすべての子プロセスを停止する方法

次の構成で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プロセス。

サービスを完全に停止するにはどうすればよいですか(つまり、すべての子プロセスが強制終了されます)?理想的には、上記の構成ファイルを変更したくありません。

6
Dhara

理想的には、上記の構成ファイルを変更したくありません。

タフ!それは正しいことです。

execscriptに変更し、パイプラインの一部としてフォークされたサブプロセスでそのpythonプログラムの実行を停止する必要があります。 このServerFault answer 埋め込みシェルスクリプトでこれを行う方法を説明します。最後の行にあるスクリプトに1つだけ変更を加えます。

exec python -u /opt/XYZ/my_prog.py 2>&1

結局のところ、標準エラーもログに記録しない理由はありません。

フォークに対処するためのこれまで以上に複雑な旋回、expect daemonsystemdに切り替えるには、デーモンがフォークするのを停止することが正しいことであるという点を見逃します。現在のカーファッフルから得られる良い点が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

参考文献

5
JdeBP

GNU/Linuxでは、通常、子プロセスはPPID(親プロセスID)を変更できるため、サービスとそれが生成したすべての子プロセスを停止する方法はありません。知る唯一の方法は、システムコールが作成されたときにプロセスを生成するためにtraceし、これらのプロセスのリストを保持することです。

Ubuntuの初期化システムupstartは、これを行いません。だからあなたの質問への答えはそれは不可能です-Ubuntuでは-なしで:

  1. そのスクリプトを変更する。
  2. どのプロセスIDがそのプロセスによって生成されるかを正確に知る。
  3. これらのプロセスIDを手動で追跡します。
  4. それらを個別に殺します。

これが、 systemd を実行するLinuxディストリビューションを実行する必要がある理由です。ご覧のとおり、systemd すべての子プロセスを追跡します そして1つのコマンドでそれらすべてを強制終了できます。これがGNU/Linuxシステム管理のあり方ですが、systemdは非常に新しく、「ここでは発明されていない」(つまり、Canonicalは発明しなかった)ため、Ubuntu使いたくない。

3
allquixotic

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

1
MariusMatutiae