Está usando “while true” para manter um script vivo uma boa ideia?

16

Estou entrando no unix de um mundo diferente e queria saber se

while true
do
  /someperlscript.pl
done

O próprio script perl possui internamente um observador de pastas / arquivos que é executado quando os arquivos são alterados no local de destino.

Isso é ( while true ) uma boa ideia? Se não, qual é a abordagem robusta preferida?

TIA

EDIT: Como isso parece ter gerado um pouco de interesse, aqui está o cenário completo. O próprio script perl vigia um diretório usando um observador de arquivos. Ao receber novos arquivos (eles chegam via rsync), ele pega o novo e o processa. Agora os arquivos recebidos podem estar corrompidos (não pergunte .. vindo de um pi de framboesa), e às vezes o processo pode não ser capaz de lidar com isso. Não sei exatamente por quê, porque ainda não conhecemos todos os cenários.

MAS - se o processo falhar por algum motivo, queremos que ele esteja em funcionamento e lide com o próximo arquivo, porque o próximo arquivo é completamente não relacionado ao anterior que pode ter causado o erro.

Normalmente, eu usaria algum tipo de captura e envolvia todo o código em torno dele para que NUNCA falhasse. Mas não tinha certeza do perl.

Pelo que entendi, usar algo como supervisord é uma boa abordagem para isso.

    
por Abhinav Gujjar 30.03.2015 / 12:41

9 respostas

20

Isso depende de quão rápido o script perl retorna. Se ele retornar rapidamente, você pode querer inserir uma pequena pausa entre as execuções para evitar a carga da CPU, por exemplo:

while true
do
  /someperlscript.pl
  sleep 1
done

Isso também impedirá que um processador oculte se o script não for encontrado ou falha imediatamente.

O loop também pode ser melhor implementado no próprio script perl para evitar esses problemas.

Editar:

Como você escreveu o loop, apenas a finalidade é reiniciar o script perl caso ele falhe, uma abordagem melhor seria implementá-lo como um serviço monitorado, mas a maneira precisa de fazer isso é dependente do sistema operacional. Por exemplo: Solaris smf, Linux systemd ou um restaurador baseado em cron.

    
por 30.03.2015 / 12:50
13

As outras respostas, sobre o uso de inotify , estão corretas, mas não uma resposta para essa pergunta.

Um supervisor de processo, como supervisord , upstart ou runit , foi projetado para exatamente o problema de assistir e reiniciar um serviço se ele falhar.

Sua distro provavelmente vem com um supervisor de processo integrado.

    
por 30.03.2015 / 17:16
11

while true é bom como uma construção "loop forever" de propósito geral. Como outras respostas dizem, o corpo do loop não deve estar vazio, ou ficar vazio em virtude do comando dentro do loop não funcionar.

Se você estiver usando o Linux, talvez queira usar um comando como inotifywait , o que torna o loop while muito mais simples:

while inotifywait -qqe modify "$DIRECTORY"
do
    process_the_directory "$DIRECTORY"
done

Aqui, o comando inotifywait ficará parado e aguardará a ocorrência de um evento do sistema de arquivos (neste exemplo, quando os arquivos no diretório são gravados). Nesse ponto, ele sai com sucesso e o corpo do loop é executado. Em seguida, volta a esperar novamente. Como o comando inotifywait aguarda que algo aconteça no diretório, é muito mais eficiente do que pesquisar continuamente o diretório.

    
por 30.03.2015 / 16:56
4

Mova o while 1 para o script perl (sugestão @roaima após)

#!/usr/bin/perl

 use Linux::Inotify2;

 my $inotify = new Linux::Inotify2 or die "unable to inotify: $!";

 $inotify->watch ("Dir", IN_MODIFY, ## or in_{acess,create,open, etc...}
   sub { my $e = shift;
     my $name = $e->fullname;
     ## whatever 
     print "$name was modified\n" if $e->IN_MODIFY;
  });

 1 while $inotify->poll;
    
por 30.03.2015 / 13:30
3

Quando seu script perl é destinado a continuar funcionando o tempo todo, por que usar a construção while? Quando o perl falha em vista de algum problema sério, o novo script perl iniciado pelo while pode travar com a mesma intensidade. De novo e de novo e assim por diante.
Se você realmente quer que seu perl seja iniciado, considere o crontab e um script que primeiro verifica se há instâncias em execução. Desta forma, o seu script será iniciado mesmo após uma reinicialização.

    
por 30.03.2015 / 13:05
2

Em geral, não há problema em usar while true , pois é um teste minúsculo que é executado somente depois que o script perl é finalizado. Tenha em mente que, dependendo de qual variante do Linux / Unix você está usando, o script pode ser encerrado ao efetuar logoff. Nesse caso, considere usar o loop em um script e chamá-lo com nohup e colocá-lo no segundo plano, ou seja, nohup myscript &

Se o script perl terminar com muita freqüência e causar carga de CPU, essa carga será responsável pelo script perl e não pelo while true .

Veja também man nohup para detalhes.

    
por 30.03.2015 / 12:51
2

Se você quiser gerenciar um processo, convém procurar um gerente de processo para fazer isso.

Com muitos sistemas recentes, você pode usar systemd para monitorar seus processos (que é um dos benefícios do systemd sobre scripts de inicialização clássicos). Se sua distro de escolha não usa systemd, você pode usar daemontools ou monit .

    
por 31.03.2015 / 12:24
2

O loop while não é uma boa ideia. Não há como fugir - apenas corre para sempre - estaticamente . Qualquer número de coisas pode mudar no ambiente e isso não será afetado - e isso pode ser ruim.

Por exemplo, se o executável do shell responsável pelo loop while for atualizado, o kernel não poderá liberar o espaço em disco para a versão antiga até que esse script seja encerrado, pois ele precisa manter o descritor contanto que seja executado. . E isso é verdade para quaisquer arquivos que o shell possa ter aberto por qualquer razão para executar o loop - todos eles serão mantidos abertos por esse loop while enquanto ele for executado - para sempre.

E se, céu proibir, há um vazamento de memória em qualquer lugar no shell que executa esse loop - mesmo o mais ínfimo - ele simplesmente continuará a vazar - estaticamente . Ele vai construir desmarcado e o único recurso é para matá-lo com força, em seguida, iniciá-lo apenas para fazer o mesmo mais tarde.

Esta não é a maneira como você deve configurar um processo em segundo plano - pelo menos, não na minha opinião. Em vez disso, como eu acho, deveria haver um ponto de redefinição - uma atualização do script e seu estado. A maneira mais fácil de fazer isso é com exec . Você pode substituir o processo atual por um novo - mantendo o mesmo PID - mas ainda executando um novo processo .

Por exemplo, se o seu script perl retornar true depois de ter manipulado com êxito uma modificação de arquivo em algum diretório monitorado:

#!/bin/sh
trap 'rm -rf -- "${ldir%%*.}"' 0 INT
_exec() case    $#      in
        (0)     exec env -  "PID=$$" "ldir=${TMPDIR:-/tmp}/." \
                            "$0" "$@";;
        (*)     export "$@" "boff=0" "lmt=30"
                exec        "$0" "$@";;
        esac
[ "$PID" = "$$" ] || _exec
[ -w "$ldir" ]  &&
case    $ldir   in
(*.)    until   mkdir -- "$ldir"
        do      :& ldir=$ldir$$$!
        done    2>/dev/null
;;
(*)     until   /someperlscript.pl ||
                [ "$((boff+=1))"  -ge "$lmt" ]
        do      [ -d "$ldir" ]     &&
                sleep "$boff"      || ! break
        done
;;esac  &&      _exec ldir PID

... ou algo parecido. Algo que permite que a maquinaria básica por trás do loop seja atualizada de vez em quando.

    
por 30.03.2015 / 18:30
1

Eu invoquei algumas dessas respostas, mas instintivamente tenho os sentimentos mais calorosos pela resposta do @ WalterA. Bem, eu fiz até criar minha própria resposta ...

Pessoalmente, tenho a tendência de atualizar o script Perl para que ele grave uma entrada de log descritiva sobre a falha e envie um alerta para um administrador.

Se o script Perl deve continuar em execução, aguardando eventos de mudança do sistema de arquivos, por que está falhando?

Se não está falhando, por que você está preocupado em envolvê-lo em um script para reiniciá-lo infinitamente?

Se houver um problema de configuração ou alguma dependência quebrada que faça com que o script Perl seja abortado, simplesmente reiniciá-lo várias vezes provavelmente não fará com que ele comece a funcionar de repente.

Você conhece a definição de insanidade, certo? (fazendo a mesma coisa repetidas vezes, esperando um resultado diferente). Apenas dizendo. ; -)

    
por 31.03.2015 / 05:16

Tags