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
Как надежно избавиться от prog1, prog2 и prog3, которые могут зависнуть и занять ресурсы, необходимые для повторной попытки?
Можно ли это сделать только в Bash или мне нужно использовать cgroups?
решение1
Это можно сделать с помощью групп процессов (рекомендуетсяздесь) и setsid
начать новый:
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
решение2
Вы можете использовать timeout
include в GNU's coreutils
:
timeout <time in second> bash -c "prog1 | prog2 | prog3"
Пример:
timeout 5 bash -c "pwd | sleep 10"
time
Чтобы убедиться, что это работает, используйте :
$ time timeout 5 bash -c "pwd | sleep 10"
real 0m5.003s
user 0m0.000s
sys 0m0.000s
решение3
Один из методов контроля за сбойным конвейером — подсчитать количество процессов конвейера через некоторое время. Если они не завершились, то закройте их и перезапустите.
В этом примере кода мы используем askБашдля идентификатора его процесса ( $$
переменной), затем используйтепгрепчтобы найти все подпроцессы скрипта. То есть, pgrep
сообщает нам все идентификаторы рабочих процессов. Если таковые имеются, то мы используем соответствующиеpkillкоманду раздавить их перед перезапуском.
Кроме того, мы используемдатакоманда для вывода наглядного файла журнала, показывающего, что и в какое время делает система.
источник: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
Тестовый забег:
запустить скрипт управления рабочим процессом
$ ./pipeline.sh &
[1] 21291
02:06:39 PM workflow starting
02:06:39 PM waiting for workflow to complete
Скрипты конвейера ждут несколько секунд, но процедуры рабочего процесса все еще работают, так как они начинаются с «sleep 30»
Pipeline обнаруживает, что рабочий процесс застрял, выдает сообщение об ошибке и завершает работу перед перезапуском.
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 теперь ожидает завершения рабочего процесса. Здесь мы схитрим и вручную завершим конвейер, убив рабочих.
$ 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
Скрипт конвейера теперь замечает, что все рабочие процессы завершены, поэтому конвейер завершен. Он создает заключительное сообщение журнала, а затем завершает работу.
02:07:16 PM workflow done!
[1]+ Done ./pipeline.sh