複数のプロセスを実行し、いずれかのプロセスが終了または失敗したときに終了する方法

複数のプロセスを実行し、いずれかのプロセスが終了または失敗したときに終了する方法

複数のプロセスを実行していて、いずれかのプロセスが失敗した場合、または存在する場合(失敗した場合はエラー、そうでなければ成功)、適切な終了コードで終了したいと思います。

また、子プロセスが終了または失敗した場合は、他の子プロセスも終了する必要があります。

現在動作していない解決策(実は単なる例であり、他のコマンドかもしれません):

#!/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 taskyarn schedule

サブプロセスが何であれ(bash、Yarn、PHP、または他のプロセス)、どのように機能させることができますか?

GNU 並列性は使用できません。

ベストアンサー1

wait組み込み関数は「何も待たず」ではなく「すべて待つ」ので、シェルではこれが痛いです。waitパラメータがない場合は、すべての子プロセスが終了するのを待って0を返します。wait明示的なプロセスリストを使用している場合は、すべての子プロセスが終了するのを待ち、最後の引数の状態を返します。複数の子供を待って子供の終了ステータスを確認するには、別のアプローチを取る必要があります。waitこれは、どの子供が死亡したかを知っている場合にのみ終了ステータスを提供します。

1つの可能なアプローチは、専用の名前付きパイプを使用して各子孫の状態を報告することです。次のコードスニペット(テストされていません!)は、最大のサブステータスを返します。

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

サブシェルの1つが状態を報告せずに死ぬと、永遠にブロックされます。これは通常の状況では発生しませんが、サブシェルが手動で終了した場合、またはサブシェルにメモリが不足している場合に発生する可能性があります。

子のいずれかが失敗したときにすぐに特定のタスクを実行するには、if [ $status -gt $max_status ]; then …に置き換えますif [ $status -ne 0 ]; then …

おすすめ記事