SSH oturumu sonlandırıldığında Python arka plan işlemim neden bitiyor?


19

Anahtar satırıyla bir python3 komut dosyası (diyelim startup.sh) başlatan bir bash komut dosyası var :

nohup python3 -u <script> &

sshDoğrudan içeri girdiğimde ve bu komut dosyasını çağırdığımda, çıktıktan sonra python komut dosyası arka planda çalışmaya devam ediyor. Ancak, bunu çalıştırdığınızda:

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

İşlem, çalışmayı bitirir bitirmez sona erer sshve oturumu kapatır.

İkisi arasındaki fark nedir?

EDIT: python betiği şişe üzerinden bir web hizmeti çalıştırıyor.

EDIT2: Ben de çağıran ve koştu , ama aynı davranış var bir init komut dosyası oluşturmaya çalıştım .startup.shssh -i <keyfile> -o StrictHostKeyChecking=no <user>@<hostname> "sudo service start <servicename>"

EDIT3: Belki de senaryoda başka bir şeydir. İşte betiğin büyük kısmı:

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: Son satır bir uyku ile son çalıştırdığınızda:

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"

Asla ulaşmaz echo "Finished"ve daha önce hiç görmediğim Şişe sunucusu mesajını görüyorum:

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

SSH'yi manuel olarak içeri alıp süreci kendim öldürürsem "Bitti" yi görüyorum.

EDIT5: EDIT4 kullanarak, herhangi bir uç noktaya bir istekte bulunursam, bir sayfa geri alıyorum, ancak Şişe hata veriyor:

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 betiğinin ne yaptığına dair daha fazla açıklama almamızın bir yolu var mı? Muhtemelen tam kaynak kodu olmadan hala tahminler alırsınız, ancak python betiğinin ne yaptığı hakkında daha fazla bilgi sahibi olmak, daha iyi eğitimli tahminler yapmamıza yardımcı olabilir.
Bratchley

Evet - soruya eklendi.
neverendingqs

Komut dosyası bir şekilde ekli terminale veya buna benzer bir şeye bağlı olarak erken bir şey yapıyor olabilir ve bu bir zamanlama sorunu olabilir: oturum ilk birkaç saniyeyi geçerse çalışır, aksi takdirde çalışmaz. En iyi seçeneğiniz strace, Linux kullanıyorsanız veya trussSolaris kullanıyorsanız ve nasıl / neden sonlandığını görmek için bunu altında çalıştırmak olabilir . Mesela ssh -i <keyfile> -o StrictHostKeyChecking=no <user>@<hostname> strace -fo /tmp/debug ./startup.sh.
Celada

&Başlangıç ​​komut dosyasının sonundaki seçeneğini kullanmayı denediniz mi? Ekleme &üst kimliği (üst kimlikler ölmesi çocuklarını ne zaman) olmaktan ssh oturumu bağımlılığını alır götürür. Ayrıca bu önceki yazı dayalı yinelenen bir soru olduğunu düşünüyorum . Bir önceki cümlede size gönderdiğim gönderi, bu gönderinin daha iyi ayrıntı verebilecek bir kopyası .
Jacob Bryan

Daha nohup ./startup.sh &önce denedim , ama aynı davranış vardı. startup.shzaten bir çatal içeriyor ( nohup python3 -u <script> &), bu yüzden tekrar çatallamaya ihtiyacım olmadığından eminim.
neverendingqs

Yanıtlar:


11

Komutu standart giriş / çıkış ve hata akışlarından ayırırdım:

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

sshdaha fazla çıktısı olmayan ve daha fazla girdi gerektirmeyen bir göstergeye ihtiyaç duyar. sshGiriş / çıkış başka bir şeye sahip olmak ve çıkış aracını yeniden yönlendirmek, giriş / çıkış terminalden gelmediği veya terminale gitmediği için güvenli bir şekilde çıkabilir. Bu, girdinin başka bir yerden gelmesi gerektiği anlamına gelir ve çıktı (STDOUT ve STDERR) başka bir yere gitmelidir.

</dev/nullParçası belirtir /dev/nulliçin girdi olarak <script>. Burada neden faydalı:

/ Dev / null komutunu stdin'e yönlendirmek, söz konusu işlemden yapılan tüm okuma çağrılarına anında bir EOF verecektir. Bu genellikle bir işlemi bir tty'den ayırmak için yararlıdır (böyle bir sürece daemon denir). Örneğin, bir arka plan işlemini ssh üzerinden uzaktan başlatırken, işlemin yerel girdiyi beklemesini önlemek için stdin'i yönlendirmeniz gerekir. /programming/19955260/what-is-dev-null-in-bash/19955475#19955475

Alternatif olarak, mevcut sshoturumun açık tutulması gerekmediği sürece başka bir giriş kaynağından yeniden yönlendirme nispeten güvenli olmalıdır .

İle >/dev/nullkısmen kabuk dev / null esas atılmadan / içine standart çıkışı yönlendirir. >/path/to/filede çalışacak.

Son bölüm 2>&1STDERR'ı STDOUT'a yönlendiriyor.

Bir program için üç standart giriş ve çıkış kaynağı vardır. Standart giriş genellikle etkileşimli bir programsa klavyeden veya diğer programın çıktısını işliyorsa başka bir programdan gelir. Program genellikle standart çıktıya, bazen de standart hataya yazdırır. Bu üç dosya tanımlayıcıya (bunları "veri boruları" olarak düşünebilirsiniz) genellikle STDIN, STDOUT ve STDERR olarak adlandırılır.

Bazen adlandırılmazlar, numaralandırılırlar! Onlar için yerleşik numaralandırmalar, bu sırayla 0, 1 ve 2'dir. Varsayılan olarak, açıkça bir isim veya numara vermezseniz, STDOUT'tan bahsedersiniz.

Bu bağlam göz önüne alındığında, yukarıdaki komutun standart çıktıyı / dev / null'a yönlendirdiğini görebilirsiniz; bu, istemediğiniz her şeyi (genellikle bit-kova olarak adlandırılır) dökebileceğiniz, ardından standart hatayı standart çıktıya ( bunu yaptığınızda hedefin önüne & önüne koymanız gerekir).

Bu nedenle kısa açıklama, “bu komuttan elde edilen tüm çıktılar bir kara deliğe itilmelidir” dir. Bu, bir programı gerçekten sessiz hale getirmenin iyi bir yoludur!
> / Dev / null 2> & 1 ne anlama geliyor? | Xaprb


nohup python3 -u <script> >/dev/null 2>&1 &ve nohup python3 -u <script> > nohup.out 2>&1 &çalıştı. Nohup'ın tüm çıktıları otomatik olarak yönlendirdiğini sanıyordum - fark nedir?
neverendingqs

@neverendingqs, nohupuzak ana bilgisayarınızda hangi sürümüne sahipsiniz? Bir POSIX nohupyönlendirmek zorunda değil stdin, ki bunu kaçırdım, ama yine de yönlendirmeli stdoutve stderr.
Graeme

Görünüţe göre çalýţýyorum nohup (GNU coreutils) 8.21.
neverendingqs

@neverendingqs, nohupgibi mesajlar yazdırıyor nohup: ignoring input and appending output to ‘nohup.out’mu?
Graeme

Evet - bu tam mesajdır.
neverendingqs

3

Şuna bak 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]

Çalıştırdığınızda ssh -i <keyfile> -o StrictHostKeyChecking=no <user>@<hostname> "./startup.sh", bir ssh komutu olarak shell script startup.sh komutunu çalıştırırsınız.

Açıklamasından:

Komut belirtilirse, oturum açma kabuğu yerine uzak ana bilgisayarda yürütülür.

Buna dayanarak, komut dosyasını uzaktan çalıştırıyor olmalıdır.

Bu ve nohup python3 -u <script> &yerel terminalinizde çalışan arasındaki fark , ssh komutu uzak bir arka plan işlemi olarak çalıştırmayı denerken bunun yerel bir arka plan işlemi olarak çalışmasıdır.

Komut dosyasını yerel olarak çalıştırmak istiyorsanız, ssh komutunun bir parçası olarak startup.sh dosyasını çalıştırmayın. Gibi bir şey deneyebilirsinizssh -i <keyfile> -o StrictHostKeyChecking=no <user>@<hostname> && "./startup.sh"

Amacınız komut dosyasını uzaktan çalıştırmaksa ve ssh oturumunuz sona erdikten sonra bu işlemin devam etmesini istiyorsanız, önce screenuzak ana bilgisayarda bir oturum başlatmanız gerekir . Sonra ekran içinde python komut dosyasını çalıştırmanız gerekir ve ssh oturumunuzu bitirdikten sonra çalışmaya devam eder.

Ekran Kullanım Kılavuzuna bakın

Ekranın en iyi seçenek olduğunu düşünüyorum, ancak nohup kullanmanız gerekiyorsa, shopt -s huponexitnohup komutunu çalıştırmadan önce uzak ana bilgisayarda ayarlamayı düşünün . Alternatif olarak, disown -h [jobID]işlemi SIGHUP öğesinin gönderilmemesi için işaretlemek için kullanabilirsiniz . 1

Arka planda bir kabuk komut isteminden çıktıktan sonra nasıl çalışmaya devam edebilirim?

SIGHUP (Hangup) sinyali sisteminiz tarafından kontrol terminalinin kontrolü veya ölüm sürecinin ölümünde kullanılır. SIGHUP öğesini yapılandırma dosyalarını yeniden yüklemek ve günlük dosyalarını açmak / kapatmak için kullanabilirsiniz. Başka bir deyişle, terminalinizden çıkış yaparsanız, çalışan tüm işler sonlandırılır. Bundan kaçınmak için -h seçeneğini reddetmekten vazgeçebilirsiniz. Bu seçenek, kabuk bir SIGHUP alırsa SIGHUP'ın işe gönderilmemesi için her iş kimliğini işaretler.

Ayrıca, huponexitbir kabuktan çıkıldığında, öldürüldüğünde veya düşürüldüğünde nasıl çalıştığının bu özetine bakın . Mevcut sorununuzun kabuk oturumunun nasıl bittiği ile ilgili olduğunu tahmin ediyorum. 2

  1. Bir ssh bağlantısı üzerinden açılan bir kabuğun arka planı olan veya olmayan tüm alt işlemler, ssh bağlantısı yalnızca huponexit seçeneği ayarlandığında kapatıldığında SIGHUP ile öldürülür: bunun doğru olup olmadığını görmek için shopt huponexit komutunu çalıştırın.

  2. Huponexit doğruysa, işlemi kabuktan ayırmak için nohup veya disown kullanabilirsiniz, böylece çıktığınızda öldürülmez. Veya ekranla bir şeyler çalıştırın.

  3. Huponexit yanlışsa, bu günlerde en azından bazı linux'larda varsayılan olan, arka plandaki işler normal çıkışta öldürülmeyecektir.

  4. Ancak huponexit yanlış olsa bile, ssh bağlantısı öldürülürse veya düşerse (normal oturumdan farklıysa), arka plandaki işlemler yine de öldürülür. Bu, (2) 'deki gibi reddedilme veya nohup ile önlenebilir.

Son olarak, shopt huponexit'in nasıl kullanılacağına dair bazı örnekler. 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

Göre bashadam sayfasında, huponexittek interaktif kabukları ve komut etkilemelidir - 'huponexit kabuk seçeneği shopt ile ayarlanan olmuşsa, bash tüm işlerin interaktif bir giriş kabuğu çıkarken bir SIGHUP gönderir.'
Graeme

2

Belki de -nbaşlamak için bir seçenek denemeye değer ssh? stdinTabii ki ssh sessionbiter bitmez kapanacak olan yerelde uzaktan işlem bağımlılığını önleyecektir . Ve bu, erişmeye çalıştığında fiyatların feshedilmesine neden olur stdin.


Başarısız denedim = [.
neverendingqs

2

Bir yarış durumunuz olduğundan şüpheleniyorum. Böyle bir şeye giderdi:

  • SSH bağlantısı başlar
  • SSH startup.sh dosyasını başlatır
  • startup.sh bir arka plan işlemi başlatır (nohup)
  • startup.sh bitirir
  • ssh biter ve bu alt süreçleri öldürür (yani nohup)

Eğer ssh işleri kısa kesmeseydi, aşağıdakiler olurdu (bu ikisinin sırasından emin değilim):

  • nohup python betiğinizi başlatır
  • nohup ana işlemden ve terminalden ayrılır.

Son iki kritik adım gerçekleşmez, çünkü nohup'dan önce startup.sh ve ssh bitirir.

Startup.sh sonunda birkaç saniye uyku koyarsanız, sorunun ortadan kalkacağını umuyorum. Tam olarak ne kadar zamana ihtiyacınız olduğundan emin değilim. Bunu minimumda tutmak önemliyse, güvenli olduğunu görmek için proc'taki bir şeye bakabilirsiniz.


İyi bir nokta, bunun için pencere olsa da çok uzun olacağını sanmıyorum - muhtemelen sadece birkaç milisaniye. Kontrol edebilirsiniz /proc/$!/commdeğil nohupveya daha taşınabilir bir çıktı kullanın ps -o comm= $!.
Graeme

Bu normal çıkış için işe yarar, ama oturumun ne zaman bırakıldığı veya öldürüldüğü zaman? Tamamen iç çekerek yok sayılmak için işi reddetmeniz gerekmez mi?
iyrin

@RyanLoremIpsum: Başlangıç ​​komut dosyasının yalnızca alt işlemin tamamen ayrılması için yeterince beklemesi gerekir. Bundan sonra, ssh oturumuna ne olduğu önemli değil. Bu gerçekleşirken kısa bir süre içinde ssh oturumunuzu başka bir şey öldürürse, bu konuda yapabileceğiniz çok şey yoktur.
mc0e

@Graeme evet, sanırım çok hızlı, ama nohup'un emin olmak için ne yaptığını yeterince bilmiyorum. Bu konuda yetkili (veya en azından bilgili ve ayrıntılı) bir kaynağa işaret etmek yararlı olacaktır.
mc0e


1

Bu daha çok, python betiğin veya pythonkendisinin . Tüm bu nohupgerçekten yapar (bar basitleştirilmesi yönlendirmeler) sadece için işleyici ayarlanmış HUPsinyalin SIG_IGNprogramını çalıştırmadan önce (yok say). Programı SIG_DFLçalıştırmaya başladıktan sonra kendi işleyicisine geri ayarlamayı veya kurmayı durduracak hiçbir şey yoktur .

Denemek isteyebileceğiniz bir şey, komutunuzu parantez içine almaktır, böylece çift çatal efekti elde edersiniz ve pythonkomut dosyanız artık kabuk işleminin bir alt öğesi değildir. Örneğin:

( nohup python3 -u <script> & )

Denemeye değer olabilecek başka bir şey de ( bashbaşka bir kabuk kullanmıyorsanız) disownyerine yerleşimi kullanmaktır nohup. Her şey belgelendiği gibi çalışıyorsa, bu aslında bir fark yaratmamalıdır, ancak etkileşimli bir kabukta bu, HUPsinyalinpython komut dosyasına önler. Reddetmeyi bir sonraki satıra veya aşağıdaki satırla aynı şekilde ekleyebilirsiniz (a'dan ;sonra ekleme ekleme &bir hatadır bash):

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

Yukarıdaki veya bazı kombinasyonları işe yaramazsa, sorunu çözmek için tek yer pythonkomut dosyasının kendisidir.


Çatal çatal etkisi yeterli mi (@ RyanLoremIpsum'un cevabına göre)?
neverendingqs

Her ikisi de sorunu çözmedi = [. Bu bir Python sorunuysa, araştırmaya nereden başlayacağınız hakkında bir fikriniz var mı (Python betiğinin çok fazlasını buraya gönderemezsiniz)?
neverendingqs

@neverendingqs, bir huponexitşeyleri kastediyorsanız, bir alt kabukta çalışmak disown, işlemin iş listesine eklenmeyeceği ile aynı etkiye sahip olmalıdır .
Graeme

@neverendingqs, cevabımı güncelledi. İle yönlendirmeler kullanmanız gerektiğini unuttunuz disown. Yine de çok fazla fark yaratacağını beklemeyin. Sanırım en iyi bahis pythonsenaryoyu değiştirmektir, böylece neden çıktığını söyler.
Graeme

Çıktıyı yeniden yönlendirmek işe yaradı ( unix.stackexchange.com/a/176610/52894 ), ancak bunu açıkça yapmak ve yapmak arasında ne fark olduğunu nohupbilmiyorum.
neverendingqs

0

Bence iş seansa bağlı. Bu sona erdiğinde, herhangi bir kullanıcı işi de sona erer.


2
Ama bu neden bir terminal almak, komutu yazmak ve çalıştırmak ve çıkmaktan farklı? Her iki oturum da kapattığımda kapatılıyor.
neverendingqs

Kabul ediyorum, bunun neden kendi terminalinizi manuel olarak kapatmaktan farklı olmadığını anlamak istiyorum.
Avindra Goolcharan

0

Eğer nohupçıkış dosyasını açabilirsiniz Eğer bir ipucu olabilir nohup.out. pythonKomut dosyasını üzerinden çalıştırdığınızda yol üzerinde olması mümkün değildir ssh.

Komut için bir günlük dosyası oluşturmayı denerdim. Kullanmayı deneyin:

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

Ben sshkomut dosyasını el ile çalıştırmak için kullanın , bu yüzden python3 yolunda olduğunu varsayalım.
neverendingqs

@neverendingqs Günlük dosyası bir şey içeriyor mu?
BillThor

Sıra dışı bir şey yok - başlangıç ​​normal görünüyor.
neverendingqs
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.