SSHセッションが終了すると、Pythonバックグラウンドプロセスが終了するのはなぜですか?


19

startup.shキーラインでpython3スクリプトを起動するbashスクリプトがあります(呼び出しましょう):

nohup python3 -u <script> &

sshこのスクリプトを直接呼び出して呼び出した場合、終了後もPythonスクリプトはバックグラウンドで実行され続けます。ただし、これを実行すると:

ssh -i <keyfile> -o StrictHostKeyChecking=no <user>@<hostname> "./startup.sh"

プロセスは実行を終了するとすぐにssh終了し、セッションを閉じます。

2つの違いは何ですか?

編集:Pythonスクリプトは、ボトル経由でWebサービスを実行しています。

EDIT2:を呼び出して実行するinitスクリプト作成しようとしましたが、同じ動作になりました。startup.shssh -i <keyfile> -o StrictHostKeyChecking=no <user>@<hostname> "sudo service start <servicename>"

EDIT3:多分それはスクリプト内の何か他のものです。スクリプトの大部分は次のとおりです。

chmod 700 ${key_loc}

echo "INFO: Syncing files."
rsync -azP -e "ssh -i ${key_loc} -o StrictHostKeyChecking=no" ${source_client_loc} ${remote_user}@${remote_hostname}:${destination_client_loc}

echo "INFO: Running startup script."
ssh -i ${key_loc} -o StrictHostKeyChecking=no ${remote_user}@${remote_hostname} "cd ${destination_client_loc}; chmod u+x ${ctl_script}; ./${ctl_script} restart"

EDIT4:最後の行を実行し、最後にスリープ状態にした場合:

ssh -i ${key_loc} -o StrictHostKeyChecking=no ${remote_user}@${remote_hostname} "cd ${destination_client_loc}; chmod u+x ${ctl_script}; ./${ctl_script} restart; sleep 1"

echo "Finished"

に到達することはなくecho "Finished"、かつて見たことのないBottleサーバーメッセージが表示されます。

Bottle vx.x.x server starting up (using WSGIRefServer())...
Listening on <URL>
Hit Ctrl-C to quit.

手動でSSHで接続し、自分でプロセスを強制終了すると、「完了」と表示されます。

EDIT5:EDIT4を使用して、エンドポイントにリクエストを行うと、ページが返されますが、ボトルはエラーになります。

Bottle vx.x.x server starting up (using WSGIRefServer())...
Listening on <URL>
Hit Ctrl-C to quit.


----------------------------------------
Exception happened during processing of request from ('<IP>', 55104)

pythonスクリプトが何をするかについての説明をもっと得る方法はありますか?おそらく、完全なソースコードがなくても推測が得られるでしょうが、Pythonスクリプトが何をするのかをもっと知ることは、より良い知識のある推測をするのに役立つかもしれません。
ブラッチリー

うん-質問に追加されました。
neverendingqs

スクリプトは、接続された端末またはそのようなものに依存する何らかの早い段階で何かを実行している可能性があり、それがタイミングの問題である可能性があります。straceLinuxを使用しtrussている場合、またはSolarisを実行していて、どのように/なぜ終了するかを確認する場合は、最適なオプションを実行することをお勧めします。例えば好きssh -i <keyfile> -o StrictHostKeyChecking=no <user>@<hostname> strace -fo /tmp/debug ./startup.sh
セラダ

&起動スクリプトの最後にを使用してみましたか?を追加する&と、sshセッションの依存関係が親IDから削除されます(親IDが消滅すると、子も消滅します)。また、これはこの以前の投稿に基づいた重複した質問だと思います。前の文であなたに提出した投稿は、この投稿の複製であり、より良い詳細を提供するかもしれません。
ジェイコブブライアン

私はnohup ./startup.sh &以前に試しましたが、同じ振る舞いをしました。startup.shにはすでにフォークが含まれているnohup python3 -u <script> &ため()、再度フォークする必要はないと確信しています。
neverendingqs

回答:


11

コマンドを標準の入出力およびエラーフローから切断します。

nohup python3 -u <script> </dev/null >/dev/null 2>&1 &  

sshこれ以上の出力を持たず、それ以上の入力を必要としないインジケータが必要です。ssh入力/出力がターミナルから来たり出たりしないので、何か他のものを入力にして出力手段をリダイレクトすることは安全に終了できます。これは、入力が他のどこかから来なければならず、出力(STDOUTとSTDERRの両方)が他のどこかに行く必要があることを意味します。

</dev/null一部には、指定/dev/nullの入力として<script>。ここでなぜそれが役立つのか:

/ dev / nullをstdinにリダイレクトすると、そのプロセスからの読み取り呼び出しに即時EOFが与えられます。これは通常、ttyからプロセスを切り離すのに役立ちます(このようなプロセスはデーモンと呼ばれます)。たとえば、sshを介してバックグラウンドプロセスをリモートで開始する場合、stdinをリダイレクトして、プロセスがローカル入力を待機しないようにする必要があります。 /programming/19955260/what-is-dev-null-in-bash/19955475#19955475

また、現在のsshセッションを開いたままにする必要がない限り、別の入力ソースからのリダイレクトは比較的安全です。

この>/dev/null部分で、シェルは標準出力を/ dev / nullにリダイレクトし、基本的にそれを破棄します。>/path/to/file動作します。

最後の部分2>&1は、STDERRをSTDOUTにリダイレクトしています。

プログラムの入力と出力には3つの標準ソースがあります。標準入力は通常、対話型プログラムの場合はキーボードから、他のプログラムの出力を処理している場合は別のプログラムから入力されます。通常、プログラムは標準出力に出力され、場合によっては標準エラーに出力されます。これらの3つのファイル記述子(「データパイプ」と考えることができます)は、しばしばSTDIN、STDOUT、およびSTDERRと呼ばれます。

時々、名前が付けられず、番号が付けられます!それらの組み込みの番号は、0、1、2の順です。デフォルトでは、明示的に名前を付けたり番号を付けたりしない場合、STDOUTについて話していることになります。

そのコンテキストを考えると、上記のコマンドが標準出力を/ dev / nullにリダイレクトしていることがわかります。これは、不要なもの(多くの場合、ビットバケットと呼ばれます)をダンプし、標準エラーを標準出力(これを行う場合、宛先の前に&を付ける必要があります)。

したがって、簡単な説明は「このコマンドからのすべての出力をブラックホールに押し込む必要がある」ということです。これは、プログラムを非常に静かにする良い方法の1つです。
> / dev / null 2>&1はどういう意味ですか?| Xaprb


nohup python3 -u <script> >/dev/null 2>&1 &そしてnohup python3 -u <script> > nohup.out 2>&1 &働いた。nohupはすべての出力を自動的にリダイレクトしますが、違いは何ですか?
neverendingqs

@neverendingqs、nohupリモートホストにはどのバージョンがありますか?A POSIXは、nohupリダイレクトするために必要とされていないstdin、私は逃した、が、それはまだリダイレクトする必要がありますstdoutstderr
グレアム14

私が働いているように見えnohup (GNU coreutils) 8.21ます。
neverendingqs

@neverendingqs、次のnohupようなメッセージを出力しますnohup: ignoring input and appending output to ‘nohup.out’か?
グレアム14

はい-それは正確なメッセージです。
neverendingqs

3

見てくださいman ssh

 ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec] [-D [bind_address:]port]
     [-e escape_char] [-F configfile] [-I pkcs11] [-i identity_file] [-L [bind_address:]port:host:hostport]
     [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port]
     [-R [bind_address:]port:host:hostport] [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]]
     [user@]hostname [command]

実行ssh -i <keyfile> -o StrictHostKeyChecking=no <user>@<hostname> "./startup.sh"すると、sshコマンドとしてシェルスクリプトstartup.shが実行されます。

説明から:

コマンドが指定されている場合、ログインシェルの代わりにリモートホストで実行されます。

これに基づいて、スクリプトをリモートで実行する必要があります。

これとnohup python3 -u <script> &ローカル端末での実行の違いは、これがローカルバックグラウンドプロセスとして実行され、sshコマンドがリモートバックグラウンドプロセスとして実行しようとすることです。

スクリプトをローカルで実行する場合は、sshコマンドの一部としてstartup.shを実行しないでください。あなたは次のようなものを試すかもしれませんssh -i <keyfile> -o StrictHostKeyChecking=no <user>@<hostname> && "./startup.sh"

スクリプトをリモートで実行することを意図しており、sshセッションが終了した後もこのプロセスを続行する場合は、最初screenにリモートホストでセッションを開始する必要があります。次に、画面内でpythonスクリプトを実行する必要があり、sshセッションを終了した後も引き続き実行されます。

スクリーンユーザーズマニュアルを参照してください

画面が最良のオプションだと思いますが、nohupを使用する必要がある場合はshopt -s huponexit、nohupコマンドを実行する前にリモートホストでの設定を検討してください。あるいは、disown -h [jobID]SIGHUPがプロセスに送信されないように、プロセスをマークするために使用できます。1

バックグラウンドでシェルプロンプトを終了した後、ジョブを実行し続けるにはどうすればよいですか?

SIGHUP(ハングアップ)シグナルは、制御端末または制御プロセスの終了時にシステムによって使用されます。SIGHUPを使用して、構成ファイルを再ロードしたり、ログファイルを開いたり閉じたりできます。つまり、ターミナルからログアウトすると、実行中のジョブはすべて終了します。これを回避するために、-hオプションをdisownコマンドに渡すことができます。このオプションは、シェルがSIGHUPを受信した場合にSIGHUPがジョブに送信されないように、各jobIDをマークします。

また、huponexitシェルが終了、強制終了、またはドロップされたときにどのように機能するかの概要を参照してください。現在の問題は、シェルセッションの終了方法に関連していると思います。2

  1. ssh接続を介して開かれたシェルのバックグラウンドであるかどうかに関係なく、すべての子プロセスは、huponexitオプションが設定されている場合にのみssh接続が閉じられると終了します。

  2. huponexitがtrueの場合、nohupまたはdisownを使用してシェルからプロセスを分離できるため、終了時にプロセスが強制終了されることはありません。または、画面で物事を実行します。

  3. 最近少なくとも一部のLinuxでデフォルトであるhuponexitがfalseの場合、通常のログアウトでバックグラウンドジョブは強制終了されません。

  4. ただし、huponexitがfalseであっても、ssh接続が強制終了またはドロップ(通常のログアウトとは異なる)した場合、バックグラウンドプロセスは強制終了されます。これは、(2)のようにdisownまたはnohupによって回避できます。

最後に、shopt huponexitの使用方法の例をいくつか示します。3

$ shopt -s huponexit; shopt | grep huponexit
huponexit       on
# Background jobs will be terminated with SIGHUP when shell exits

$ shopt -u huponexit; shopt | grep huponexit
huponexit       off
# Background jobs will NOT be terminated with SIGHUP when shell exits

bashマニュアルページによると、huponexitスクリプトではなく対話型シェルのみに影響するはずです-「huponexitシェルオプションがshoptで設定されている場合、bashは対話型ログインシェルの終了時にすべてのジョブにSIGHUPを送信します。」
グレアム

2

-n開始するときにオプションを試してみる価値があり ますsshか?stdinもちろん、終了するとすぐに閉じるlocalへのリモートプロセスの依存を防ぎssh sessionます。そしてこれはそれがアクセスしようとするたびにリモート価格終了を引き起こしますstdin


成功せずに試してみました= [。
neverendingqs

2

競合状態にあると思われます。次のようになります。

  • SSH接続が開始されます
  • SSHはstartup.shを開始します
  • startup.shはバックグラウンドプロセスを開始します(nohup)
  • startup.shが終了します
  • sshが終了し、これにより子プロセスが終了します(つまりnohup)

sshが短くなっていないと、次のことが起こります(これら2つの順序がわからない)。

  • nohupはPythonスクリプトを開始します
  • nohupは親プロセスと端末から切断します。

そのため、startup.shとsshはnohupが処理を行う前に完了するため、最後の2つの重要なステップは発生しません。

startup.shの最後に数秒のスリープを設定すると、問題はなくなると思います。どれだけの時間が必要なのか正確にはわかりません。最小限に抑えることが重要な場合は、procの何かを見て、いつ安全かを確認できます。


良い点は、このウィンドウが非常に長くなるとは思わないことです。おそらく数ミリ秒にすぎません。の出力が使用されて/proc/$!/commいないnohupか、より移植性があることを確認できps -o comm= $!ます。
グレアム14

これは通常のログアウトでは機能するはずですが、セッションがドロップまたは強制終了された場合はどうでしょうか?仕事を否認する必要はないので、ため息で完全に無視されますか?
iyrin 14

@RyanLoremIpsum:起動スクリプトは、子プロセスが完全に切り離されるまで待つだけで済みます。その後、sshセッションがどうなるかは関係ありません。それが起こっている間に他の何かが短いウィンドウであなたのsshセッションを強制終了した場合、あなたはそれに対してできることはあまりありません。
mc0e

@Graemeええ、私はそれが非常に速いと思いますが、私はnohupが確実に何をするかについて正確に十分に知りません。これに関する信頼できる(または少なくとも知識が豊富で詳細な)ソースへのポインタが役立ちます。
mc0e 14


1

これは、pythonスクリプトまたはpythonそれ自体が実行していることに関する問題のように聞こえます。そのすべてnohupは本当にありません(バー簡素化リダイレクトは)ただのハンドラ設定されているHUPに信号をSIG_IGN、プログラムを実行する前に(無視します)。プログラムSIG_DFLが実行を開始したら、プログラムを停止したり、独自のハンドラをインストールしたりすることはできません。

試したいことの1つは、コマンドをかっこで囲み、ダブルフォーク効果を得て、pythonスクリプトがシェルプロセスの子にならないようにすることです。例えば:

( nohup python3 -u <script> & )

試してみる価値があるもう1つのことは(bash別のシェルではなく使用している場合)、disown代わりに組み込みを使用することですnohup。すべてが文書通りに機能している場合、これは実際には何の違いも生じませんが、インタラクティブシェルでは、これはHUP信号がpythonスクリプトに伝播するのを停止します。次の行にdisownを追加するか、以下と同じ行にdisownを追加できます(;後にaを追加する&とにエラーが発生しますbash)。

python3 -u <script> </dev/null &>/dev/null & disown

上記またはその組み合わせが機能しない場合、問題に対処する唯一の場所はpythonスクリプト自体です。


ダブルフォーク効果で十分ですか(@RyanLoremIpsumの回答に基づく)?
neverendingqs

両方とも問題を解決しませんでした= [。Pythonの問題である場合、調査を開始する場所についてのアイデアはありますか(Pythonスクリプトの多くをここに投稿できません)。
neverendingqs

@neverendingqs、つまりhuponexit、サブシェルで実行するdisownと、プロセスがジョブリストに追加されないのと同じ効果があります。
Graeme 14

@neverendingqs、私の答えを更新しました。でリダイレクトを使用する必要があることを忘れていましたdisown。しかし、それが大きな違いを生むと期待しないでください。最善の策は、pythonスクリプトを変更して、終了する理由を伝えることです。
グレアム14

出力のリダイレクトは機能しました(unix.stackexchange.com/a/176610/52894)が、明示的に実行することと実行することの違いがnohupわからない。
neverendingqs

0

仕事はセッションに関係しているからだと思います。それが終了すると、すべてのユーザージョブも終了します。


2
しかし、なぜ端末を取得し、コマンドを入力して実行し、終了するのと違うのですか?一度閉じると、両方のセッションが閉じられます。
neverendingqs

同意します。これが、自分の端末を手動で閉じるのと何の違いもないのかを理解したいと思います。
アビンドラグールチャラン14

0

場合はnohup、その出力ファイルを開くことができますでの手掛かりを持っていることnohup.outpython経由でスクリプトを実行すると、パス上にない可能性がありますssh

コマンドのログファイルを作成してみます。使用してみてください:

nohup /usr/bin/python3 -u <script> &>logfile &

sshはスクリプトを手動で実行するために使用するので、python3がパスにあると想定しています。
neverendingqs

@neverendingqsログファイルには何かが含まれていますか?
BillThor 14年

異常なことは何もありません。起動は正常に見えます。
neverendingqs
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.