while true; do
# process substitution instead of usual pipeline to avoid waiting for all programs
handle_input_with_timeout < <( prog1 | prog2 | prog3 )
echo "Data stopped flowing. Trying again"
# perminate stuck programs in previous pipeline, then try again
sleep 5
done
Como se livrar de forma confiável de prog1, prog2 e prog3 que podem travar e reter os recursos necessários para tentar novamente?
Isso pode ser feito apenas no Bash ou preciso usar cgroups?
Responder1
Isso pode ser feito com grupos de processos (sugeridoaqui) e setsid
para iniciar um novo:
while true; do
handle_input_with_timeout < <( setsid bash -c '
printf -- "-$$" > /tmp/saved_process_group.pid
prog1 | prog2 | prog3
')
echo "Data stopped flowing. Trying again"
kill -9 $(< /tmp/saved_process_group.pid )
sleep 5
done
Responder2
Você pode usar timeout
incluir em GNU's coreutils
:
timeout <time in second> bash -c "prog1 | prog2 | prog3"
Exemplo:
timeout 5 bash -c "pwd | sleep 10"
Use time
para ter certeza de que funciona:
$ time timeout 5 bash -c "pwd | sleep 10"
real 0m5.003s
user 0m0.000s
sys 0m0.000s
Responder3
Uma técnica para controlar um pipeline errôneo é contar o número de processos de pipeline após um tempo. Se eles não terminaram, ataque-os e reinicie.
Neste código de exemplo usamos askBashpara seu ID de processo (a $$
variável), então usepgreppara encontrar todos os subprocessos do script. Ou seja, pgrep
nos informa todos os IDs do processo de fluxo de trabalho. Se houver algum, então usamos o correspondentematarcomando para esmagá-los antes de reiniciar.
Além disso, usamos odatacomando para gerar um arquivo de log bonito, mostrando o que o sistema está fazendo e a que horas.
fonte:https://github.com/shavenwarthog/johntellsall/tree/master/karma/kill-pipeline
#!/bin/bash
# pipeline.sh -- start workflow; restart if jammed
while true; do
date '+%X workflow starting'
(sleep 30; echo gin) &
(sleep 30; echo tonic) &
date '+%X waiting for workflow to complete'
sleep 5
# count number of child procs (ie: workflow procs)
# If there are any, kill them then restart.
if pgrep -cP $$ > /dev/null ; then
date '+%X workflow jammed -- restarting; trying again'
pkill -P $$
sleep 2
continue
fi
date '+%X workflow done!'
break
done
Execução de teste:
iniciar script de controle de fluxo de trabalho
$ ./pipeline.sh &
[1] 21291
02:06:39 PM workflow starting
02:06:39 PM waiting for workflow to complete
Os scripts do pipeline aguardam alguns segundos, mas os processos do fluxo de trabalho ainda estão em execução, pois começam com um "sleep 30"
O Pipeline detecta que o fluxo de trabalho está congestionado, reclama e os elimina antes de reiniciar.
02:06:44 PM workflow jammed -- restarting; trying again
./pipeline.sh: line 27: 21293 Terminated ( sleep 30; echo gin )
./pipeline.sh: line 27: 21294 Terminated ( sleep 30; echo tonic )
02:06:46 PM workflow starting
02:06:46 PM waiting for workflow to complete
O pipeline agora está aguardando a conclusão do fluxo de trabalho. Aqui vamos trapacear e completar manualmente o pipeline matando os trabalhadores.
$ pkill -f sleep
./pipeline.sh: line 27: 21363 Terminated sleep 30
./pipeline.sh: line 27: 21365 Terminated sleep 5
./pipeline.sh: line 27: 21364 Terminated sleep 30
tonic
O script do pipeline agora percebe que todos os trabalhadores terminaram, portanto, o pipeline está concluído. Ele emite uma mensagem de log final e sai.
02:07:16 PM workflow done!
[1]+ Done ./pipeline.sh