Come riavviare automaticamente lo script Python se viene ucciso o muore


31

Sto eseguendo il mio script Python in background nella mia macchina Ubuntu (12.04) in questo modo -

nohup python testing.py > test.out &

Ora, potrebbe essere possibile che ad un certo punto il mio sopra Python scriptpossa morire per qualsiasi motivo.

Quindi sto pensando di avere una sorta di cron agentscript shell bash che può riavviare automaticamente il mio script Python sopra se viene ucciso per qualsiasi motivo.

È possibile farlo? Se sì, qual è il modo migliore per risolvere questo tipo di problema?

AGGIORNARE:

Dopo aver creato il testing.conffile in questo modo -

chdir /tekooz
exec python testing.py
respawn

Ho eseguito il comando sudo sotto per avviarlo ma non riesco a vedere quel processo in esecuzione dietro usando ps ax?

root@bx13:/bezook# sudo start testing
testing start/running, process 27794
root@bx13:/bezook# ps ax | grep testing.py
27806 pts/3    S+     0:00 grep --color=auto testing.py

Qualche idea sul perché px ax non mi mostri nulla? E come posso verificare se il mio programma è in esecuzione o no?

Questo è il mio script Python -

#!/usr/bin/python
while True:
    print "Hello World"
    time.sleep(5)

Risposte:


24

Su Ubuntu (fino al 14.04, 16.04 e successivi usa systemd) puoi usare upstart per farlo, meglio di un cron job. Metti una configurazione di configurazione /etc/inite assicurati di specificare respawn

Potrebbe essere un file minimo /etc/init/testing.conf(modifica come root):

chdir /your/base/directory
exec python testing.py
respawn

E puoi provare con /your/base/directory/testing.py:

from __future__ import print_function

import time

with open('/var/tmp/testing.log', 'a') as fp:
    print(time.time(), 'done', file=fp)
    time.sleep(3)

e inizia con:

sudo start testing

e segui cosa succede (in un'altra finestra) con:

tail -f /var/tmp/testing.log

e basta con:

sudo stop testing

È inoltre possibile aggiungere [start on][2]per avviare il comando all'avvio del sistema.


Se usi un cron job, ti consigliamo di implementare o trovare del codice per la gestione dei file PID. Volete che il vostro servizio / script / demone crei un file PID (posizionato in modo convenzionale in / var / run) e che il suo codice di avvio controlli se il contenuto del file è obsoleto (lasciato da un processo interrotto). Questo tipo di codice è sorprendentemente difficile da scrivere senza razze e casi d'angolo. stackoverflow.com/questions/788411/…
Jim Dennis il

@Zelda: Grazie per il suggerimento .. Sono nuovo nel mondo Linux / Unix .. Che tipo di modifiche dovrei fare nel /etc/initfile? Se puoi fornirmi una guida passo passo per me, allora sarò in grado di imparare qualcosa e fare la cosa giusta ..
arsenal

@Webby ho reso la risposta più completa. Se non si desidera aprire un file per l'output e riscrivere le dichiarazioni di stampa, è possibile fare qualcosa come sys.stdout = open(file_name, 'w')all'inizio.
Zelda,

Grazie Zelda. Apprezzato il tuo aiuto .. Ho aggiornato la domanda con alcuni dettagli .. Sto cercando di fare in questo modo per vedere se il mio testing.py è in esecuzione o meno .. Non mi mostra se è in esecuzione o no .. px ax | grep testing.py.. Non mi sta restituendo niente? Qualche idea sul perché?
arsenale,

Dovresti mettere il tutto in una clausola try / tranne e scrivere in un file di registro quale eccezione è stata generata e che il programma esce. Forse l'istruzione print non funziona in quanto non può scrivere su stdout.
Zelda,

20

Potresti anche adottare un approccio più orientato alla shell. Cerca il crontuo copione e riavvialo se muore.

  1. Crea un nuovo crontab eseguendo crontab -e. Verrà visualizzata una finestra del tuo editor di testo preferito.

  2. Aggiungi questa riga al file appena aperto

    */5 * * * * pgrep -f testing.py || nohup python /home/you/scripts/testing.py > test.out
  3. Salvare il file ed uscire dall'editor.

Hai appena creato un nuovo crontabche verrà eseguito ogni 5 minuti e avvierai il tuo script a meno che non sia già in esecuzione. Vedi qui per un piccolo tutorial su cron. I documenti ufficiali di Ubuntu su cronsono qui .

Il comando effettivo in esecuzione è pgrepche cerca i processi in esecuzione per la stringa fornita nella riga di comando. pgrep foocercherà un programma chiamato fooe restituirà il suo identificatore di processo . pgrep -flo fa cercare nell'intera riga di comando utilizzata per avviare il programma e non solo il nome del programma (utile perché si tratta di uno script Python).

Il ||simbolo significa "fallo se il comando precedente non è riuscito". Quindi, se il tuo script non è in esecuzione, pgrepfallirà poiché non troverà nulla e il tuo script verrà avviato.


Grazie .. Ma sono nuovo di Linux e Unix, quindi non sai dove si trova crontab? È un file nella mia macchina Ubuntu da qualche parte?
arsenale,

@Webby vedi risposta aggiornata.
Terdon

Grazie terdon .. Posso eseguire questo comando crontab -edalla directory in cui il mio script Python è .. Corretto?
arsenale,

1
@Webby puoi eseguirlo ovunque tu voglia. cronè un demone di pianificazione, è un servizio che viene eseguito in background. Se il tuo script Python non è nel tuo $PATH(se non puoi avviarlo da nessuna parte ma devi trovarlo nella sua directory) usa il percorso completo dello script come nella mia risposta aggiornata.
Terdon

Grazie. Ora ha senso .. Ho appena creato un nuovo crontab e modificato il file aggiungendo la stessa riga singola ma per 1 minuto .. Ho già creato uno script Hello World Python che gira mentre True si chiama testing.py .. Dopo aver salvato il file crontab, dovrebbe iniziare automaticamente testing.py dopo 1 minuto? E poi continua a controllare ogni 1 minuto se lo script python è in esecuzione o no? Se sì, dopo aver salvato il file crontab -e, ho fatto ps ax | grep testing.py e non riesco a vedere alcun processo per quello?
arsenale,

6

Puoi fare in modo che il programma di test reindirizzi l'output utilizzando un'opzione della riga di comando e quindi utilizzare un semplice script Python per riavviare il programma indefinitamente:

import subprocess

while True:
    try:
        print subprocess.check_output(['python', 'testing.py'])
    except KeyboardInterrupt:
        break

puoi mettere questo programma in background e una volta che vuoi smettere basta tirarlo in primo piano e ucciderlo.


6

Non dovresti davvero usarlo per la produzione, ma potresti:

#!/bin/sh

while true; do
  nohup python testing.py >> test.out
done &

Se, per qualsiasi motivo, il processo python viene chiuso, il ciclo della shell continuerà e lo riavvierà, aggiungendo il .outfile come desiderato. Quasi nessun sovraccarico e richiede pochissimo tempo per l'installazione.


6

Esistono diversi modi per monitorare e rigenerare i processi in UNIX / Linux. Una delle più vecchie è una voce "respawn" in / etc / inittab ... se stai usando il vecchio sistema SysV init. Un altro metodo consiste nell'utilizzare il demone supervisore dal pacchetto daemontools di DJ Bernstein . Altre opzioni sono usare le funzionalità di Ubuntu upstart ... o systemd o altri.

Ma puoi guardare alternative init e nel codice Python per Pardus: il demone mudur in particolare.

Se decidi di andare con un lavoro cron (e gestione dei file PID), considera la lettura di questo PEP 3143 e forse la sua implementazione di riferimento.

Come ho accennato nei miei altri commenti, la solida gestione dei file PID è complicata. È soggetto a gare e casi d'angolo. Diventa più complicato se c'è qualche possibilità che il tuo file PID finisca su un NFS o su un altro filesystem di rete (parte dell'atomicità ti garantisce che la semantica della gestione dei file sui file system UNIX / Linux locali appropriati scompaia su alcune versioni e implementazioni di NFS, per esempio). Anche la semantica relativa al blocco dei file in UNIX può essere complicata. (Un blocco flocko fcntlviene rilasciato prontamente, nel sistema operativo di destinazione, ad esempio quando il processo che lo trattiene viene interrotto con SIGKILL?).


3

Puoi anche usare il monitoraggio di monit o di processo con ps-watcher

Monit è un'utilità open source per la gestione e il monitoraggio di processi, programmi, file, directory e filesystem su un sistema UNIX. Monit effettua manutenzione e riparazione automatiche e può eseguire azioni causali significative in situazioni di errore.

Ecco un esempio per il tuo scenario:

check process myprocessname
        matching "myprocessname"
        start program = "nohup /usr/bin/python /path/testing.py > /tmp/test.out &"
        stop program = "/usr/bin/killall myprocessname"

Dai un'occhiata agli esempi di monit


1

È necessario un supervisore, è possibile utilizzare il supervisore . È un supervisore basato su Python, quindi facile da modificare se necessario.

Il controllo è con file con sintassi di file .ini.


0

La risposta di Terdon, non ha funzionato per me, perché pgrep -f testing.pynon ha mai "fallito". Afferrerebbe il pid per il processo cron (a causa dell'opzione -f). Tuttavia, senza l'opzione -f pgrep non troverà testing.py perché non esiste un processo chiamato testing.py.

La mia soluzione era cambiare

pgrep -f testing.py

a

pgrep -f testing.py | pgrep python

questo significa che il lavoro crontab completo sarebbe:

*/5 * * * * pgrep -f testing.py | pgrep python || nohup python /home/you/scripts/testing.py > test.out

0

Nel mio caso, come soluzione rapida, volevo mantenere il mio programma in esecuzione quando è uscito con un errore o è stato ucciso. D'altra parte, volevo interrompere l'esecuzione quando il programma è terminato correttamente (codice di ritorno = 0)

L'ho provato su Bash. Dovrebbe funzionare bene in qualsiasi altra shell

#!/bin/sh

echo ""
echo "Use: $0 ./instagram.py"
echo ""

echo "Executing $1 ..."

EXIT_CODE=1
(while [ $EXIT_CODE -gt 0 ]; do
    $1
    # loops on error code: greater-than 0
    EXIT_CODE=$?
done)

0

Per la risposta di Terdon, pgrep -f testing.pynon restituirà mai false in base ai commenti qui :

Penso che il problema sia che cron genera una shell per eseguire il tuo comando, e gli argomenti di quella shell sono abbinati a pgrep poiché stai usando -f

Per la risposta di Matt, pgrep -f testing.pyè inutile poiché pgrep pythoncorrisponde a qualsiasi script Python in esecuzione. Quindi, se due cronjob di script Python, il secondo cronjob non verrà mai eseguito.

E poi ho trovato la soluzione da risolvere pgrep -f testing.pynel commento qui: https://askubuntu.com/questions/1014559/running-pgrep-in-a-crontab?noredirect=1&lq=1

Il mio cron per l'esecuzione di due script Python:

* * * * * pgrep -f '^/usr/bin/python36 /home/ec2-user/myscript1\.py' || nohup /usr/bin/python36 /home/ec2-user/myscript1.py

0 * * * * pgrep -f '^/usr/bin/python36 /home/ec2-user/myscript2\.py' || nohup /usr/bin/python36 /home/ec2-user/myscript2.py
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.