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 中完成还是需要使用 cgroup?
答案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
包含在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重击为其进程 ID($$
变量),然后使用正则表达式查找脚本的所有子流程。也就是说,pgrep
告诉我们所有工作流程 ID。如果有,那么我们使用相应的杀戮命令在重新启动之前压缩它们。
此外,我们使用日期命令输出一个漂亮的日志文件,显示系统在什么时间正在做什么。
来源: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”开始
管道检测到工作流程被堵塞,抱怨并在重新启动之前终止它们。
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
管道现在正在等待工作流程完成。在这里,我们将通过杀死工人来手动完成管道。
$ 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