Como enviar SIGKILLs para todo o pipeline?

6
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 do prog1, prog2 e prog3 de forma confiável que pode ficar preso e manter os recursos necessários para tentar novamente?

Isso pode ser feito apenas no Bash ou eu preciso usar cgroups?

    
por Vi. 09.05.2014 / 14:18

3 respostas

5

Isso pode ser feito com grupos de processos (sugeridos aqui ) 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
    
por 09.05.2014 / 16:50
4

Você pode usar timeout include em GNU's coreutils :

timeout <time in second> bash -c "prog1 | prog2 | prog3"

Exemplo:

timeout 5 bash -c "pwd | sleep 10"

Use time para se certificar de que funciona:

$ time timeout 5 bash -c "pwd | sleep 10"

real    0m5.003s
user    0m0.000s
sys     0m0.000s
    
por 09.05.2014 / 15:44
0

Uma técnica para controlar um pipeline errante é contar o número de processos de pipeline depois de um tempo. Se eles não tiverem terminado, então aperte-os e reinicie.

Neste código de exemplo, usamos Bash para obter o ID do processo ( $$ variável), use pgrep para encontrar todos os subprocessos do script. Ou seja, pgrep nos informa todos os IDs do processo de fluxo de trabalho. Se houver, usaremos o comando pkill correspondente para eliminá-los antes do reinício.

Além disso, usamos o comando data para exibir um arquivo de log bonito, mostrando o que o sistema está fazendo a qualquer momento.

source : link

#!/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

Teste executado :

inicie o script de controle do fluxo de trabalho

$ ./pipeline.sh &

[1] 21291

02:06:39 PM workflow starting

02:06:39 PM waiting for workflow to complete

Os scripts de pipeline aguardam alguns segundos, mas os procs de 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 mata antes do reinício.

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 está aguardando a conclusão do fluxo de trabalho. Aqui nós vamos trapacear e manualmente completar o processo 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 de pipeline agora percebe que todos os trabalhadores estão prontos, portanto, o pipeline está pronto. Ele faz uma mensagem de log conclusiva e sai.

02:07:16 PM workflow done!

[1]+ Done ./pipeline.sh

    
por 09.05.2014 / 23:30