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

31

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

nohup python testing.py > test.out &

Agora, é possível que, em algum momento, minha descrição Python scriptpossa morrer por qualquer motivo.

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

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

ATUALIZAR:

Depois de criar o testing.confarquivo assim -

chdir /tekooz
exec python testing.py
respawn

Corri abaixo do comando sudo para iniciá-lo, mas não consigo ver esse processo atrasado 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 idéia de por que px ax não está me mostrando nada? E como verifico 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)
arsenal
fonte

Respostas:

24

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

Pode ser um arquivo mínimo /etc/init/testing.conf(edite 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 que o comando seja iniciado na inicialização do sistema.

Zelda
fonte
Se você usar um trabalho cron, será necessário implementar ou encontrar algum código para manipulação robusta de arquivos PID. Você deseja que seu service / script / daemon crie um arquivo PID (localizado convencionalmente em / var / run) e faça com que seu código de inicialização verifique se o conteúdo do arquivo está obsoleto (deixado por um processo interrompido). Esse tipo de código é surpreendentemente difícil de escrever, sem corridas e caixas de canto. stackoverflow.com/questions/788411/…
Jim Dennis
@Zelda: Obrigado pela sugestão. Sou novo no mundo Linux / Unix. Que tipo de alterações devo fazer no /etc/initarquivo? Se você puder fornecer guia passo a passo para mim, então eu serei capaz de aprender algo e fazer a coisa certa ..
arsenal
@Webby Eu fiz a resposta mais completa. Se você não deseja abrir um arquivo para saída e reescrever suas instruções de impressão, pode fazer algo como sys.stdout = open(file_name, 'w')no início.
Zelda em
Obrigado Zelda. Agradeço sua ajuda .. Atualizei a pergunta com alguns detalhes .. Estou tentando fazer assim para ver se meu testing.py está em execução ou não. Ele não mostra se está em execução ou não px ax | grep testing.py. Não está me devolvendo nada? Alguma idéia do porquê?
Arsenal
Você deve colocar a coisa toda em uma cláusula try / except e gravar em um arquivo de log qual exceção foi gerada e que o programa sai. Talvez a declaração de impressão não funcione, pois não pode gravar em stdout.
Zelda
20

Você também pode adotar uma abordagem mais orientada a shell. Ter o seu cronolhar para o seu script e relançá-lo se ele morre.

  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 crontabque será executado a cada 5 minutos e iniciará seu script, a menos que ele já esteja em execução. Veja aqui um pequeno tutorial sobre cron. Os documentos oficiais do Ubuntu cronestão aqui .

O comando real pgrepque está sendo executado é o que procura processos em execução pela cadeia de caracteres fornecida na linha de comandos. pgrep fooprocurará um programa nomeado fooe retornará seu identificador de processo . pgrep -ffaz com que pesquise toda a linha de comando usada para iniciar o programa e não apenas o nome do programa (útil porque este é um script python).

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

terdon
fonte
Obrigado .. Mas eu sou novo no linux e no unix, então não sei onde está o crontab? Este arquivo está na minha máquina ubuntu em algum lugar?
arsenal
@Webby veja resposta atualizada.
terdon
Obrigado terdon .. Eu posso executar este comando crontab -eno diretório em que meu script python está .. Correto?
arsenal
11
@ Webby você pode executá-lo de qualquer lugar que desejar. croné um daemon de agendamento, é um serviço executado em segundo plano. Se o seu script python não estiver no seu $PATH(se você não puder iniciá-lo em qualquer lugar, mas precisar estar em seu diretório), use o caminho completo para o script, como na minha resposta atualizada.
terdon
Obrigado. Agora faz sentido .. Acabei de criar um novo crontab e editei o arquivo adicionando a mesma linha única, mas por 1 minuto .. Já criei um script Hello World Python girando em torno de enquanto True nomeado como testing.py .. Depois de salvar o arquivo crontab, ele deve iniciar automaticamente o testing.py após 1 minuto? E continue verificando a cada 1 minuto se o script python está sendo executado ou não? Se sim, depois de salvar o arquivo crontab -e, fiz ps ax | grep testing.py e não consigo ver nenhum processo para isso?
arsenal
6

Você pode fazer com que o programa de teste redirecione a saída usando uma opção de linha de comando e 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 esse programa em segundo plano e, quando quiser parar, basta puxá-lo para o primeiro plano e matá-lo.

Anthon
fonte
6

Você realmente não deve usar isso para produção, mas pode:

#!/bin/sh

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

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

K3 --- rnc
fonte
6

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

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

Se você optar por executar uma tarefa cron (e manipulação de arquivos PID), considere ler este PEP 3143 e talvez usar sua implementação de referência.

Como mencionei em meus outros comentários, o manuseio robusto de arquivos PID é complicado. É propenso a corridas e caixas de esquina. Fica mais complicado se houver alguma chance de o seu arquivo PID terminar em um NFS ou outro sistema de arquivos em rede (parte da atomicidade garante que você obtenha a semântica de manipulação de arquivos em sistemas de arquivos UNIX / Linux locais adequados que desaparecem em 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 bloqueio flockou fcntlé liberado imediatamente, no sistema operacional de destino, quando o processo que o mantém é interrompido com o SIGKILL, por exemplo?).

Jim Dennis
fonte
3

Você também pode usar o monitoramento monit Or Process com o ps-watcher

O Monit é um utilitário de código aberto para gerenciar e monitorar processos, programas, arquivos, diretórios e sistemas de arquivos em um sistema UNIX. A Monit realiza manutenção e reparo automáticos e pode executar ações causais significativas em situações de erro.

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 de monit

Rahul Patil
fonte
1

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

O controle é com arquivos com sintaxe de arquivo .ini.

user41123
fonte
0

A resposta de Terdon não funcionou para mim, porque pgrep -f testing.pynunca 'falhou'. Ele pegaria o pid para o trabalho cron (por causa da opção -f). No entanto, sem a opção -f, o pgrep não encontrará o testing.py porque não há 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 do crontab seria:

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

No meu caso, como uma solução rápida, eu queria manter meu programa em execução quando ele saiu com um erro de erro ou foi morto. Por outro lado, eu queria interromper a execução quando o programa foi finalizado 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)
user9869932
fonte
0

Para a resposta de terdon, pgrep -f testing.pynunca retornará falso de acordo com os comentários aqui :

Eu acho que a questão é que o cron gera um shell para executar seu comando, e os argumentos desse shell são correspondidos pelo pgrep desde que você esteja usando -f

Para a resposta de Matt, pgrep -f testing.pyé inútil, pois pgrep pythoncorresponde a qualquer script Python em execução. Portanto, se o cronjob de dois scripts Python, o segundo cronjob nunca será executado.

E então eu encontrei a solução para resolver pgrep -f testing.pyno comentário aqui: https://askubuntu.com/questions/1014559/running-pgrep-in-a-crontab?noredirect=1&lq=1

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
Frank
fonte