Eu tenho um script python que verificará uma fila e executará uma ação em cada item:
# checkqueue.py
while True:
check_queue()
do_something()
Como escrevo um script bash que verifica se está sendo executado e, se não estiver, inicie-o. Aproximadamente o seguinte pseudo-código (ou talvez deva fazer algo assim ps | grep
?):
# keepalivescript.sh
if processidfile exists:
if processid is running:
exit, all ok
run checkqueue.py
write processid to processidfile
Vou chamar isso de um crontab:
# crontab
*/5 * * * * /path/to/keepalivescript.sh
Respostas:
Evite arquivos PID, crons ou qualquer outra coisa que tente avaliar processos que não são filhos deles.
Há uma boa razão pela qual, no UNIX, você só pode esperar seus filhos. Qualquer método (ps parsing, pgrep, armazenando um PID, ...) que tente solucionar o problema é defeituoso e possui buracos escancarados. Apenas diga não .
Em vez disso, você precisa do processo que monitora seu processo para ser o pai do processo. O que isto significa? Isso significa que apenas o processo que inicia o processo pode esperar com segurança que ele termine. No bash, isso é absolutamente trivial.
A parte acima do código do bash é executada
myserver
em umuntil
loop. A primeira linha iniciamyserver
e aguarda o término. Quando termina,until
verifica seu status de saída. Se o status de saída for0
, significa que ele terminou normalmente (o que significa que você solicitou o desligamento de alguma forma e o fez com êxito). Nesse caso, não queremos reiniciá-lo (apenas pedimos para desligar!). Se o status de saída não for0
,until
executará o corpo do loop, que emite uma mensagem de erro no STDERR e reinicia o loop (de volta à linha 1) após 1 segundo .Por que esperamos um segundo? Porque se algo estiver errado com a sequência de inicialização
myserver
e ela travar imediatamente, você terá um loop muito intenso de reinicializações e travamentos constantes em suas mãos. Osleep 1
tira a tensão disso.Agora tudo o que você precisa fazer é iniciar esse script bash (de forma assíncrona, provavelmente), e ele será monitorado
myserver
e reiniciado conforme necessário. Se você deseja iniciar o monitor na inicialização (fazendo o servidor "sobreviver" à reinicialização), é possível agendá-lo no cron (1) do usuário com uma@reboot
regra. Abra suas regras cron comcrontab
:Em seguida, adicione uma regra para iniciar o script do seu monitor:
Alternativamente; veja inittab (5) e / etc / inittab. Você pode adicionar uma linha para
myserver
iniciar em um determinado nível de inicialização e ser reaparecida automaticamente.Editar.
Deixe-me adicionar algumas informações sobre por que não usar arquivos PID. Enquanto eles são muito populares; eles também são muito falhos e não há razão para que você não faça da maneira correta.
Considere isto:
Reciclagem de PID (acabando com o processo errado):
/etc/init.d/foo start
: iniciefoo
, escrevafoo
o PID para/var/run/foo.pid
foo
morre de alguma forma.bar
) leva um PID aleatório, imagine-o usandofoo
o antigo PID.foo
foi:/etc/init.d/foo/restart
lê/var/run/foo.pid
, checa para ver se ainda está vivo, achabar
, acha que estáfoo
, mata, inicia um novofoo
.Os arquivos PID ficam obsoletos. Você precisa de lógica excessivamente complicada (ou devo dizer, não trivial) para verificar se o arquivo PID está obsoleto e se essa lógica está novamente vulnerável
1.
.E se você nem tiver acesso de gravação ou estiver em um ambiente somente leitura?
É supercomplicação inútil; veja como é simples o meu exemplo acima. Não há necessidade de complicar isso.
Veja também: Os arquivos PID ainda são defeituosos ao fazê-lo 'certo'?
A propósito; ainda pior do que os arquivos PID está analisando
ps
! Nunca faça isso.ps
é muito portável. Enquanto você o encontra em quase todos os sistemas UNIX; seus argumentos variam muito se você deseja saída fora do padrão. E a saída padrão é APENAS para consumo humano, não para análise por script!ps
leva a muitos falsos positivos. Pegue ops aux | grep PID
exemplo e agora imagine alguém iniciando um processo com um número em algum lugar, como argumento que é o mesmo que o PID com o qual você olhou seu daemon! Imagine duas pessoas iniciando uma sessão do X e você esperando que o X mate a sua. É apenas todo tipo de coisa ruim.Se você não deseja gerenciar o processo sozinho; existem alguns sistemas perfeitamente bons por aí que atuam como monitor para seus processos. Veja runit , por exemplo.
fonte
while true; do myprocess; done
mas observe que agora não há como parar o processo.trap 'kill $(jobs -p)' EXIT; until myserver & wait; do sleep 1; done
Dê uma olhada no monit ( http://mmonit.com/monit/ ). Ele lida com iniciar, parar e reiniciar seu script e pode fazer verificações de saúde e reiniciar, se necessário.
Ou faça um script simples:
fonte
A maneira mais fácil de fazer isso é usando o rebanho em arquivo. No script Python você faria
No shell, você pode realmente testar se está em execução:
Mas é claro que você não precisa testar, porque se ele já estiver em execução e você o reiniciar, ele sairá com
'other instance already running'
Quando o processo morre, todos os seus descritores de arquivo são fechados e todos os bloqueios são removidos automaticamente.
fonte
flock
... de fato, a página de manual demonstra explicitamente como!exec {lock_fd}>/tmp/script.lock; flock -x "$lock_fd"
é o equivalente do bash ao seu Python e deixa o bloqueio retido (portanto, se você executar um processo, o bloqueio permanecerá retido até que o processo termine).flock
é a maneira correta, mas seus scripts estão errados. O único comando que você precisa definir no crontab é:flock -n /tmp/script.lock -c '/path/to/my/script.py'
Você deve usar o monit, uma ferramenta unix padrão que pode monitorar coisas diferentes no sistema e reagir de acordo.
Nos documentos: http://mmonit.com/monit/documentation/monit.html#pid_testing
Você também pode configurar o monit para lhe enviar um email quando ele reiniciar.
fonte
fonte
ps ax|grep ...
. Você pode simplesmente instalá-lo ou escrever uma função para isso: psgrep function () {ps ax | grep -v grep | grep -q "$ 1"}Não sei ao certo como é portátil em todos os sistemas operacionais, mas você pode verificar se o seu sistema contém o comando 'run-one', ou seja, "man run-one". Especificamente, esse conjunto de comandos inclui 'executar um constantemente', que parece ser exatamente o que é necessário.
Na página do manual:
Nota: obviamente isso pode ser chamado de dentro do seu script, mas também elimina a necessidade de ter um script.
fonte
Eu usei o seguinte script com grande sucesso em vários servidores:
notas:
$INSTALLATION
contém o suficiente do caminho do processo, é totalmente inequívocoNa verdade, esse script é usado para desligar uma instância em execução do tomcat, que eu quero desligar (e esperar) na linha de comando; portanto, iniciá-lo como um processo filho simplesmente não é uma opção para mim.
fonte
grep | awk
ainda é um antipadrão - você desejaawk "/$INSTALLATION/ { print \$1 }"
combinar o inútilgrep
com o script Awk, que pode encontrar linhas pela própria expressão regular muito bem, muito obrigado.Eu uso isso para o meu processo npm
fonte