如何运行多个进程并在其中任何进程退出或失败时退出

如何运行多个进程并在其中任何进程退出或失败时退出

我正在运行多个进程,并且希望在其中任何一个进程失败或存在时以适当的退出代码退出(这意味着失败时出错,否则成功)。

此外,如果任何子进程退出或失败,任何其他子进程也应该关闭。

我当前的非功能性解决方案(yarn 只是一个示例;可能是任何其他命令):

#!/bin/bash -e

# Run other process before start
sh ./bin/optimize.sh

trap 'exit' INT TERM
trap 'kill -INT 0' EXIT

# Run Schedule
sh ./bin/schedule.sh &
# Run a long running task
yarn task &

wait

./bin/schedule.sh:

#!/bin/bash -e

while true; do
  yarn schedule
  sleep 30
done

如果某件事yarn schedule失败了,一切都会正确存在。但是当我通过ctrl+杀死进程cyarn task退出时,进程yarn schedule会继续运行。

无论子进程是什么(bash、yarn、php 或其他进程),如何使其正常工作?

我无法使用 GNU 并行。

答案1

这在 shell 中是很痛苦的,因为wait内置函数不会“等待任何”,而是“等待所有”。wait如果不带参数,则等待所有子进程退出,并返回 0。wait如果使用显式进程列表,则等待所有子进程退出,并返回最后一个参数的状态。要等待多个孩子并获取他们的退出状态,您需要采用不同的方法。wait仅当您知道哪个孩子已经死亡时,才能为您提供退出状态。

一种可能的方法是使用专用的命名管道来报告每个子项的状态。以下代码片段(未经测试!)返回最大的子级状态。

mkfifo status_pipe
children=0
{ child1; echo 1 $? >status_pipe; } & children=$((children+1))
{ child2; echo 2 $? >status_pipe; } & children=$((children+1))
max_status=0
while [ $children -ne 0 ]; do
  read -r child status <status_pipe
  children=$((children-1))
  if [ $status -gt $max_status ]; then
    max_status=$status
  fi
done
rm status_pipe

请注意,如果其中一个子 shell 死亡且未报告其状态,则这将永远阻塞。在典型情况下不会发生这种情况,但如果手动终止子 shell,或者子 shell 内存不足,则可能会发生这种情况。

如果您想在其中一个子级失败时立即执行某些操作,请替换if [ $status -gt $max_status ]; then …if [ $status -ne 0 ]; then …

答案2

GNU 并行有--halt.如果其中一个作业完成或终止,它将终止所有正在运行的作业,如果作业失败,它将返回 false:

parallel --halt now,done=1 ::: 'sleep 1;echo a' 'sleep 2;echo b' ||
  echo the job that finished failed

parallel --halt now,done=1 ::: 'sleep 1;echo a;false' 'sleep 2;echo b' ||
  echo the job that finished failed

对于未安装 GNU Parallel 的系统,您通常可以在以下系统上编写脚本:GNU Parallel,并用于--embed将 GNU Parallel 直接嵌入到脚本中:

parallel --embed > myscript.sh

相关内容