Como reiniciar o script Python automaticamente se ele é morto ou morre

26

Estou executando meu script Python em segundo plano na minha máquina Ubuntu (12.04) assim -

nohup python testing.py > test.out &

Agora, pode ser possível que em algum momento meu Python script acima possa morrer por qualquer motivo.

Então, estou pensando em ter algum tipo de cron agent no bash shell script, que pode reiniciar meu script Python acima automaticamente se ele for morto por qualquer motivo.

Isso é possível? Se sim, então qual é a melhor maneira de resolver esse tipo de problema?

ATUALIZAÇÃO:

Depois de criar o arquivo testing.conf como este -

chdir /tekooz
exec python testing.py
respawn

Eu corri abaixo do comando sudo para iniciá-lo, mas não consigo ver esse processo sendo executado usando o 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

Alguma ideia de por que o px ax não está me mostrando nada? E como faço para verificar se meu programa está sendo executado ou não?

Este é o meu script python -

#!/usr/bin/python
while True:
    print "Hello World"
    time.sleep(5)
    
por arsenal 05.01.2014 / 08:33

10 respostas

20

No Ubuntu (até 14.04, 16.04 e posterior use o systemd) pode usar o upstart para fazer isso, melhor que um cron job. Você coloca uma configuração de configuração em /etc/init e certifique-se de especificar respawn

Pode ser um arquivo mínimo /etc/init/testing.conf (editar como root ):

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

E você pode testar com /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 comece com:

sudo start testing

e siga o que acontece (em outra janela) com:

tail -f /var/tmp/testing.log

e pare com:

sudo stop testing

Você também pode adicionar [start on][2] para ter o comando iniciado na inicialização do sistema.

    
por 05.01.2014 / 08:59
16

Você também pode adotar uma abordagem mais orientada para shell. Peça para o seu cron procurar pelo seu script e reiniciá-lo se ele morrer.

  1. Crie um novo crontab executando crontab -e . Isso abrirá uma janela do seu editor de texto favorito.

  2. Adicione esta linha ao arquivo que acabou de abrir

    */5 * * * * pgrep -f testing.py || nohup python /home/you/scripts/testing.py > test.out
    
  3. Salve o arquivo e saia do editor.

Você acabou de criar um novo crontab , que será executado a cada 5 minutos e iniciará seu script, a menos que já esteja em execução. Veja aqui para um pequeno tutorial sobre cron . Os documentos oficiais do Ubuntu sobre cron são aqui .

O comando real que está sendo executado é pgrep , que pesquisa processos em execução para a cadeia de caracteres fornecida na linha de comando. pgrep foo procurará um programa chamado foo e retornará seu identificador de processo . pgrep -f faz com que ele pesquise toda a linha de comando usada para iniciar o programa e não apenas o nome do programa (útil porque é um script python).

O símbolo || significa "faça isto se o comando anterior falhou". Portanto, se o seu script não estiver em execução, o pgrep falhará, pois não encontrará nada e seu script será iniciado.

    
por 05.01.2014 / 10:24
6

Existem várias maneiras de monitorar e reaparecer processos no UNIX / Linux. Um dos mais antigos é uma entrada "respawn" em / etc / inittab ... se você estiver usando o antigo sistema init SysV. Outro método é usar o daemon supervisor do pacote daemontools do DJ Bernstein. Outras opções são usar recursos no Ubuntu upstart ... ou systemd ou outros.

Mas você pode olhar para alternativas init e no código Python para Pardus: mudur daemon em particular.

Se você decidir trabalhar com o cron (e lidar com arquivos PID), considere a leitura deste PEP 3143 e talvez usando sua implementação de referência.

Como eu aludi nos meus outros comentários, o manuseio robusto de arquivos PID é complicado. É propenso a corridas e casos de canto. Fica mais complicado se houver alguma chance de seu arquivo PID acabar em um NFS ou outro sistema de arquivos em rede (algumas das garantias de atomicidade que você obtém com a semântica de manipulação de arquivos em sistemas de arquivos UNIX / Linux corretos desaparecem algumas versões e implementações do NFS, por exemplo). Além disso, a semântica em torno do bloqueio de arquivos no UNIX pode ser complicada. (Um flock ou fcntl lock é liberado imediatamente, no seu sistema operacional de destino, quando o processo que o mantém é morto com o SIGKILL, por exemplo?).

    
por 05.01.2014 / 08:58
6

Você pode fazer com que o programa de teste redirecione a saída usando uma opção de linha de comando e, em seguida, use um script python simples para reiniciar o programa indefinidamente:

import subprocess

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

você pode colocar este programa em segundo plano e, quando quiser parar, basta puxá-lo para o primeiro plano e eliminá-lo.

    
por 05.01.2014 / 09:16
5

Você não deveria usar isso para produção, mas poderia:

#!/bin/sh

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

Se, por algum motivo, o processo python sair, o loop do shell continuará e o reiniciará, anexando ao arquivo .out conforme desejado. Quase sem sobrecarga e leva muito pouco tempo para configurar.

    
por 05.01.2014 / 13:17
3

Você também pode usar monit ou Monitoramento de processo com o ps-watcher

Monit is an open source utility for managing and monitoring, processes, programs, files, directories and filesystems on a UNIX system. Monit conducts automatic maintenance and repair and can execute meaningful causal actions in error situations.

Aqui está um exemplo para o seu cenário:

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

Veja exemplos monit

    
por 05.01.2014 / 10:43
1

Você precisa de um supervisor, você pode usar o supervisor . É um supervisor baseado em python, portanto, fácil de modificar se você precisar.

O controle está com arquivos com a sintaxe do arquivo .ini.

    
por 05.01.2014 / 11:59
0

No meu caso, como uma correção rápida, eu queria manter meu programa em execução quando saía com erro ou ele foi morto. Por outro lado, eu queria parar a execução quando o programa terminasse corretamente (código de retorno = 0)

Eu testei no Bash. Deve funcionar bem em qualquer outro 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)
    
por 27.12.2018 / 13:53
0

Para a resposta de terdon, pgrep -f testing.py nunca retornará false de acordo com os comentários em aqui :

I think the issue is that cron spawns a shell to run your command, and the arguments of that shell are matched by pgrep since you are using -f

Para a resposta de Matt, pgrep -f testing.py é inútil, pois pgrep python corresponde a qualquer script Python em execução. Então, se duas tarefas de script do script Python, o segundo cronjob nunca será executado.

E então eu encontrei a solução para resolver pgrep -f testing.py no comentário aqui: link

Meu cron para executar dois scripts 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
    
por 08.03.2019 / 20:28
0

A resposta de Terdon, não funcionou para mim, porque pgrep -f testing.py nunca foi 'reprovado'. Ele pegaria o pid para o cron job (por causa da opção -f). No entanto, sem a opção -f, o pgrep não encontrará o arquivo testing.py porque não existe um processo chamado testing.py.

Minha solução para isso foi mudar

pgrep -f testing.py

para

pgrep -f testing.py | pgrep python

isso significa que o trabalho completo de crontab seria:

*/5 * * * * pgrep -f testing.py | pgrep python || nohup python /home/you/scripts/testing.py > test.out
    
por 15.06.2017 / 22:00