Tubo de passagem com tempo limite

3

Como posso implementar um tempo limite quando nenhum dado está sendo passado por um pipe? Ele atuaria como watchdog com o seguinte uso:

process1 | watchdog --timeout 60 | process2

Quando nenhum canal de dados passar, eu gostaria que o processo do watchdog fosse fechado.

Obrigado!

    
por Tynix 18.11.2016 / 07:46

3 respostas

2

Para começar, o pipeline de watchdog da sua pergunta provavelmente não mataria o process1 , a menos que ele esteja tentando gravar novamente no pipe morto. Então o seu cão de guarda deveria de alguma forma explicitamente matar o process1.

Além disso, há um script shell watchdog.sh muito simples. Você pode testá-lo interativamente no console. Apenas digite ./watchdog.sh . Ele duplicará tudo o que você digitar e parará se você não digitar algo por 5 segundos.

#!/bin/bash

# first arg is timeout (default: 5)
T="${1:-5}"
PID=$$

exec tee >(bash -c '
while true ; do
    bytes=$(timeout '$T' cat | wc -c)
    if ! [ "$bytes" -gt 0 ] ;then
            break
    fi
done
## add something like "killall process1", for now we just kill this tee command
kill -9 '$PID)

Note que o script irá, na verdade, expirar entre T e 2 * T (caso contrário, seria muito mais complicado). De alguma forma, você poderia adicionar uma forma de matar process1 como mencionei inicialmente.

Abaixo um exemplo para teste.

process1.sh:

#!/bin/bash

echo "here we are ..."
sleep 2
echo "still alive ..."
sleep 20
echo "too late ..."

E execute-o assim (inclusive um método feio para matar o process1.sh no tempo limite):

(./process1.sh & echo $! >/tmp/pid; wait) |(./watchdog.sh 5; kill 'cat /tmp/pid')
    
por 18.11.2016 / 12:20
0

Isso pode não ser ideal em termos de desempenho e é baseado em linha, mas o recurso de tempo limite do comando read pode ser usado para isso. Em bash , você pode usar uma sub-rotina de linha de comando como a seguinte como sua watchdog --timeout 60 part:

while read -r -s -t 60 line ; do printf "%s\n" "$line" ; done

zsh oferece um comando read semelhante.

Observe, no entanto, que ele não terminará o comando geral até que a primeira parte, ou seja, o process1 , decida encerrar devido ao fechamento da saída padrão.

    
por 18.11.2016 / 09:11
0

Uma visão alternativa do problema pode ser remover o watchdog do pipe e determinar o horário da última modificação no pipe. Por exemplo,

(
process1 &
pid=$!
old=0
while   new=$(stat -L /dev/stderr -c %Y)
        [ $new != $old ]
do      old=$new
        sleep 60
done 3>&2 2>&1 1>&3   &&   kill -hup $pid
) |
process2

Isso coloca process1 em segundo plano para que possamos obter seu pid e, em seguida, sondar o horário da última modificação do pipe de saída. Se não mudar em 60 segundos, podemos matar o pid. Para poder capturar a saída de stat , nós trocamos o descritor de arquivo 1, que é o pipe, com stderr e stat que, ao invés disso.

    
por 18.11.2016 / 19:58

Tags