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
Wie kann man zuverlässig die Programme prog1, prog2 und prog3 loswerden, die hängen bleiben und die für einen erneuten Versuch erforderlichen Ressourcen beanspruchen können?
Kann dies nur in Bash durchgeführt werden oder muss ich cgroups verwenden?
Antwort1
Dies kann mit Prozessgruppen erfolgen (empfohlenHier) und setsid
um ein Neues zu beginnen:
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
Antwort2
Sie können timeout
include in verwenden GNU's coreutils
:
timeout <time in second> bash -c "prog1 | prog2 | prog3"
Beispiel:
timeout 5 bash -c "pwd | sleep 10"
time
Um sicherzustellen, dass es funktioniert, verwenden Sie :
$ time timeout 5 bash -c "pwd | sleep 10"
real 0m5.003s
user 0m0.000s
sys 0m0.000s
Antwort3
Eine Methode zur Kontrolle einer fehlerhaften Pipeline besteht darin, nach einer Weile die Anzahl der Pipeline-Prozesse zu zählen. Wenn sie noch nicht fertig sind, löschen Sie sie und starten Sie sie neu.
In diesem Beispielcode verwenden wir askSchlagfür die Prozess-ID (die $$
Variable) und verwenden Sie dannpgrepum alle Unterprozesse des Skripts zu finden. Das heißt, pgrep
es gibt uns alle Workflow-Prozess-IDs. Wenn es welche gibt, verwenden wir die entsprechendenpkillBefehl, um sie vor einem Neustart zu beseitigen.
Darüber hinaus nutzen wir dieDatumBefehl zum Ausgeben einer hübschen Protokolldatei, die zeigt, was das System zu welchem Zeitpunkt tut.
Quelle: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
Testlauf:
Starten des Workflow-Steuerungsskripts
$ ./pipeline.sh &
[1] 21291
02:06:39 PM workflow starting
02:06:39 PM waiting for workflow to complete
Die Pipeline-Skripte warten einige Sekunden, aber die Workflow-Prozesse laufen noch, da sie mit „sleep 30“ beginnen.
Die Pipeline erkennt, dass der Workflow blockiert ist, beschwert sich darüber und beendet ihn vor einem Neustart.
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
Die Pipeline wartet nun auf den Abschluss des Workflows. Hier schummeln wir und vervollständigen die Pipeline manuell, indem wir die Worker beenden.
$ 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
Das Pipeline-Skript erkennt nun, dass alle Worker fertig sind, also ist die Pipeline fertig. Es erstellt eine abschließende Protokollmeldung und wird dann beendet.
02:07:16 PM workflow done!
[1]+ Done ./pipeline.sh