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
¿Cómo deshacerse de manera confiable de prog1, prog2 y prog3 que pueden quedarse atascados y retener los recursos necesarios para volver a intentarlo?
¿Se puede hacer solo en Bash o necesito usar cgroups?
Respuesta1
Esto se puede hacer con grupos de procesos (sugeridoaquí) y setsid
para empezar uno nuevo:
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
Respuesta2
Puedes utilizar timeout
incluir en GNU's coreutils
:
timeout <time in second> bash -c "prog1 | prog2 | prog3"
Ejemplo:
timeout 5 bash -c "pwd | sleep 10"
Utilice time
para asegurarse de que funcione:
$ time timeout 5 bash -c "pwd | sleep 10"
real 0m5.003s
user 0m0.000s
sys 0m0.000s
Respuesta3
Una técnica para controlar una tubería errónea es contar la cantidad de procesos de la tubería después de un tiempo. Si no han terminado, elimínelos y reinicie.
En este código de ejemplo usamos preguntarIntentopara su identificación de proceso (la $$
variable), luego usepgreppara encontrar todos los subprocesos del script. Es decir, pgrep
nos dice todos los ID de los procesos de flujo de trabajo. Si hay alguno, entonces utilizamos el correspondiente.matarcomando para aplastarlos antes de reiniciar.
Además, utilizamos elfechacomando para generar un bonito archivo de registro, que muestra qué está haciendo el sistema y en qué momento.
fuente: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
Prueba de funcionamiento:
iniciar script de control de flujo de trabajo
$ ./pipeline.sh &
[1] 21291
02:06:39 PM workflow starting
02:06:39 PM waiting for workflow to complete
Los scripts de canalización esperan unos segundos, pero los procesos de flujo de trabajo aún se están ejecutando, ya que comienzan con un "suspensión 30".
Pipeline detecta que el flujo de trabajo está bloqueado, se queja y lo 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
Pipeline ahora está esperando que se complete el flujo de trabajo. Aquí haremos trampa y completaremos manualmente la tubería matando a los trabajadores.
$ 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
La secuencia de comandos de canalización ahora advierte que todos los trabajadores han terminado, por lo que la canalización finaliza. Emite un mensaje de registro final y luego sale.
02:07:16 PM workflow done!
[1]+ Done ./pipeline.sh