¿Cómo matar un programa si no produjo ningún resultado en un tiempo de espera determinado?

4

Quiero detectar cuando algún proceso está atascado, pero no me da ninguna pista al respecto. Todo lo que sé es que si no produce ningún resultado en un tiempo de espera determinado (digamos 30 segundos), significa que probablemente esté bloqueado.

Conozco el timeoutprograma coreutils , pero se basa en el tiempo de salida completo del programa, no en la última línea de tiempo de salida. Me encantaría si algo como esto funcionara:

timeout --stdout --stderr 30s my-program

Entonces, ¿hay alguna manera de hacer eso? ¿Cómo puedo hacerlo?

Yajo
fuente
Me gusta la idea, pero no puedo señalar una herramienta existente. Esto no debería ser difícil de hacer per se.
tripleee
Puede encontrar esto útil.
Wobbly

Respuestas:

3

El código

Guarde esto como tkill(hágalo ejecutable y ajuste su PATHsi es necesario):

#!/bin/bash

_terminate_children() {
        trap "exit 143" SIGTERM && kill -- -$$
}

trap _terminate_children SIGINT SIGTERM

tout="$1"
shift
eval $@ | tee >(while :; do
   read -t "$tout"
   case $? in
      0) : ;;
      1) break ;;
      *) _terminate_children ;;
   esac
done)
exit ${PIPESTATUS[0]}

Uso básico

tkill 30 some_command

El primer argumento ( 30aquí) es el tiempo de espera en segundos.


Notas

  • tkillespera some_commandgenerar salida de texto (no binario).
  • tkillsondas stdoutdel comando dado. Para incluir stderrredirigirlo como en el último ejemplo avanzado a continuación.

Uso avanzado

Estos son ejemplos válidos:

tkill 9 foo -option value
tkill 9 "foo -option value"  # equivalent to the above
tkill 5 "foo | bar"
tkill 5 'foo | bar'
tkill 5 'foo | bar | baz'    # tkill monitors baz
tkill 5 'foo | bar' | baz    # baz reads from tkill
tkill 3 "foo; bar"
tkill 6 "foo && bar || baz"
tkill 7 "some_command 2>&1"

Use la sintaxis de Bash en estas citas.


Estado de salida

  • Si some_commandsale solo, su estado de salida se reutilizará como el estado de salida de tkill; tkill 5 truevuelve 0; tkill 5 falsevuelve 1; tkill 5 "true; false"vuelve 1.
  • Si el tiempo de espera expirado o tkilles interrumpido por SIGINTo SIGTERMentonces el estado de salida será 143.

Fragmentos de código explicados

  • eval hace posibles los ejemplos avanzados.
  • teenos permite analizar stdinmientras le pasamos una copia stdout.
  • read -t es responsable de aplicar el tiempo de espera, su estado de salida se utiliza para determinar qué hacer a continuación.
  • Los comandos que se supervisan se eliminan cuando es necesario con esta solución .
  • El estado de salida de los comandos monitoreados se recupera con esta solución .
Kamil Maciorowski
fuente
0

Entonces, básicamente algo como esto:

#!/bin/bash
tmp1=/tmp/tmp-$$-1
tmp2=/tmp/tmp-$$-2
touch $tmp1
touch $tmp2

time_out=30

typeset -i i

i=0
my-program > $tmp1 &
pgmpid=$!

while ps $pgmpid > /dev/null ; do
    sleep 1
    if diff $tmp1 $tmp2 > /dev/null ; then
        i=i+1
        if [ $i -gt $time_out ] ; then
            kill $pgmpid
        fi
    else
        i=0
        cp $tmp1 $tmp2 
    fi
done

rm -f $tmp1 $tmp2
Ljm Dullaart
fuente
Esto debería ser el truco, aunque esperaba algo TBH de una sola línea ... ¡Gracias de todos modos!
Yajo
0

Ejecute el programa en segundo plano mientras copia la salida a un archivo. Después de 30 segundos, si el archivo está vacío, finalice el programa; de lo contrario, vuelva a ponerlo en primer plano.

my-program | tee temp-file & 
sleep 30
[ -s temp-file ] && kill $! || fg $!
Lubo Kanev
fuente
Con esto, si después de 30 segundos se congela, no tienes suerte, ¿verdad?
Yajo
Sí. Parece que entendí mal la pregunta.
Lubo Kanev